클래스 정의를 선언에서 자동으로 분리합니까?
-
19-08-2019 - |
문제
나는 거의 전적으로 구성된 도서관을 사용하고 있습니다. 헤더 파일의 템플릿 클래스 및 기능, 이와 같이:
// foo.h
template<class T>
class Foo {
Foo(){}
void computeXYZ() { /* heavy code */ }
};
template<class T>
void processFoo(const Foo<T>& foo) { /* more heavy code */ }
이제 이것은 나쁘기 때문입니다 컴파일 시간은 견딜 수 없습니다 해당 헤더 파일 중 하나를 포함 할 때마다 (실제로 각 컴파일 장치에 많은 것을 포함).
템플릿 매개 변수로서 각 라이브러리 헤더 파일에 대해 하나 또는 두 가지 유형 만 사용합니다. 선언 만 포함하는 파일, 중공 코드가 없으면 다음과 같은 것입니다.
// NEW: fwd-foo.h
template<class T>
class Foo {
Foo();
void computeXYZ();
};
template<class T>
void processFoo(const Foo<T>& foo);
그런 다음 필요한 모든 인스턴스를 생성하는 하나의 파일. 그 파일이 될 수 있습니다 한 번에 별도로 편집되었습니다:
// NEW: foo.cpp
#include "foo.h"
template class Foo<int>;
template class Foo<double>;
template void processFoo(const Foo<int>& foo);
template void processFoo(const Foo<double>& foo);
이제 나는 그냥 포함 할 수 있습니다 fwd-foo.h
내 코드에서 짧은 컴파일 시간이 있습니다. 나는 반대 할 것이다 foo.o
결국.
물론 단점은이 새로운 것을 만들어야한다는 것입니다. fwd-foo.h
그리고 foo.cpp
스스로 파일. 물론 유지 보수 문제입니다. 새 라이브러리 버전이 출시되면 해당 새 버전에 적응해야합니다. 다른 단점이 있습니까?
그리고 나의 주요 질문은 다음과 같습니다.
이 새 파일을 만들 수있는 기회가 있습니까? fwd-foo.h
, 자동으로 원본에서 foo.h
? 많은 라이브러리 헤더 파일 (아마도 20 정도)에 대해이 작업을 수행해야하며 특히 새 라이브러리 버전이 출시되고 새 버전으로 다시 수행 해야하는 경우 자동 솔루션이 가장 좋습니다. 이 작업에 사용할 수있는 도구가 있습니까?
편집하다:
추가 질문 : 새로 지원할 수있는 방법 extern
키워드이 경우에 도움이 되나요?
해결책
우리는 사용 lzz 단일 파일을 별도의 헤더 및 번역 장치로 나눕니다. 기본적으로 일반적으로 템플릿 정의를 헤더에도 넣지 만이를 원하지 않도록 지정할 수 있습니다.
사용할 수있는 방법을 보여주기 위해 다음을 고려하십시오.
// t.cc
#include "b.h"
#include "c.h"
template <typename T>
class A {
void foo () {
C c;
c.foo ();
b.foo ();
}
B b;
}
위 파일을 가져 와서 't.lzz'파일로 복사하십시오. 배치하십시오 #포함 필요에 따라 별도의 $ HDR 및 $ SRC 블록으로 지시 :
// t.lzz
$hdr
#include "b.h"
$end
$src
#include "c.h"
$end
template <typename T>
class A {
void foo () {
C c;
c.foo ();
b.foo ();
}
B b;
}
이제 마지막으로 템플릿 정의를 소스 파일에 배치하도록 지정하는 파일에서 lzz를 실행하십시오. a를 사용 하여이 작업을 수행 할 수 있습니다 $ Pragma 소스 파일에서 또는 명령 줄 옵션 "-ts"를 사용할 수 있습니다.
이로 인해 다음 파일이 생성됩니다.
// t.h
//
#ifndef LZZ_t_h
#define LZZ_t_h
#include "b.h"
#undef LZZ_INLINE
#ifdef LZZ_ENABLE_INLINE
#define LZZ_INLINE inline
#else
#define LZZ_INLINE
#endif
template <typename T>
class A
{
void foo ();
B b;
};
#undef LZZ_INLINE
#endif
그리고:
// t.cpp
//
#include "t.h"
#include "c.h"
#define LZZ_INLINE inline
template <typename T>
void A <T>::foo ()
{
C c;
c.foo ();
b.foo ();
}
#undef LZZ_INLINE
그런 다음 일부 Grep/SED 명령을 통해 실행하여 LZZ Helper 매크로를 제거 할 수 있습니다.
다른 팁
사전 컴파일 된 헤더를 사용해보십시오. GCC와 MSVC 가이 기능을 지원한다는 것을 알고 있습니다. 그러나 사용량은 벤더에 따라 다릅니다.
나는 꽤 오랫동안 같은 문제를 해결하고 있습니다. 제안하는 솔루션에서는 템플릿 클래스를 두 번 정의하는 것입니다. 동일한 순서 (동일한 순서로)를 정의하면 괜찮지 만 조만간 문제가 발생할 수 있습니다.
내가 생각해 낸 것은 다른 방법으로 문제를 고려하는 것입니다. 구현을 전문으로하지 않는 한 우아하게 작동합니다.
AVOIS는 구현 파일에서 템플릿 인수를 업데이트 해야하는 두 개의 매크로를 사용합니다 (기본 템플릿 인수를 클래스에 추가하려면 조심하십시오).
// foo.h
#define FOO_TEMPLATE template<typename T>
#define FOO_CLASS Foo<T>
FOO_TEMPLATE
class Foo {
Foo();
void computeXYZ();
};
// foo_impl.h
#include "foo.h"
FOO_TEMPLATE
FOO_CLASS::Foo(){}
FOO_TEMPLATE
void FOO_CLASS::computeXYZ() { /* heavy code */ }
이렇게하면 본질적으로 비 테일 플레이트 클래스와 동일한 방식으로 작업합니다 (물론 템플릿 함수로 동일한 작업을 수행 할 수 있습니다).
편집 : C ++ 0X의 외부 키워드 정보
C ++ 0X의 외부 키워드가 도움이 될 것이라고 생각하지만 모든 것을 마술처럼 해결하지는 않습니다!
에서 이 기사,
외부 템플릿
템플릿을 인스턴스화하는 모든 모듈은 본질적으로 객체 코드에서 사본을 생성합니다. 그런 다음 마지막 단계에서 모든 중복 객체 코드를 폐기하는 것은 링커에 달려있어 프로그래머의 날 (또는 때로는 공상)을 구성하는 임계 편집 컴파일 링크주기가 느려집니다. 이 객체 코드 쓰레기 수집을 단락시키기 위해 많은 컴파일러 공급 업체가 이미 템플릿 앞에서 갈 수있는 외부 키워드를 구현했습니다. 이것은 기존 산업 관행을 체계화하는 표준화의 경우입니다 (PUN 의도). 실제로, 이것은 기본적으로 "여기에 인스턴스화하지 않는다"는 통지를 기본적으로 통지를 보내서 구현됩니다.
extern template class std::vector;
C ++ 0X는 외부 템플릿으로 컴파일 시간 문제를 해결합니다. 그래도 당신이 요구하는 일을하는 자동적인 방법을 모르겠습니다.