C++ 外部模板&;不完全类型
最近,当我试图优化include层次结构时,我偶然发现了文件C++ 外部模板&;不完全类型,c++,templates,c++11,incomplete-type,C++,Templates,C++11,Incomplete Type,最近,当我试图优化include层次结构时,我偶然发现了文件a.hpp: template<class T> class A { using t = typename T::a_t; }; class B; extern template class A<B>; #include <b.hpp> template class A<B>; 这样我就不必从a.hpp中包含b.hpp,这似乎是减少编译时间的好主意。但是它不工作(a.hpp本身
a.hpp
:
template<class T>
class A
{
using t = typename T::a_t;
};
class B;
extern template class A<B>;
#include <b.hpp>
template class A<B>;
这样我就不必从a.hpp
中包含b.hpp
,这似乎是减少编译时间的好主意。但是它不工作(a.hpp本身不编译!)有更好的方法吗
注意:当然我不能使用显式模板实例化,但这不是我想要的!如果使用了A
,我想“预编译”以节省编译时间,但如果未使用A
,我不想在使用A.hpp
的每个文件中都包含b.hpp
最后一个外部模板类A告诉编译器,在某些编译单元中有这样一个模板专门化的声明。编译器继续运行,然后链接器应该抱怨没有找到正确的类。它不是形式错误的;这取决于用例。您可以在一个单独的cpp文件中定义模板a。如果您反复编译它,这显然只会减少一点编译时间。您可以使用不同的结构:
一个a.hpp,仅包含a类模板
一个b.cpp文件,其中包含类b及其.h文件。(它是一个模板吗?)
b、 cpp包含一个.hpp,在里面你做了一个显式模板实例化模板类a;(与extern无关)
此时,无论何时需要使用该模板,都可以编写
外部模板类A
并链接已编译的b.cpp文件。如果由于仍然需要模板而包含了a.hpp文件,则由于使用了extern命令,因此不会重新编译该文件。extern模板声明阻止实例化成员函数体,但它强制实例化类定义,因为编译器无论如何都需要它,而且类主体需要模板参数的完整定义,因为它访问其成员。我担心对A
的用户隐藏B的身体是不可能的
extern模板是一种优化,但它不会改变实例化机制的基本工作方式。From
用于声明的显式实例化的外部说明符
类模板仅抑制定义的显式实例化
以前未专门化的成员函数和静态数据成员的
在包含声明的翻译单元中
因此,如果a中需要B的定义,您不能在不了解B的情况下使用外部模板
。您当然可以尝试摆脱该要求。在给定的情况下,可以使用t
声明删除,并使用元函数生成该类型:
template<typename T>
struct get_a_t;
template<typename T>
struct get_a_t<A<T>>
{
using type = typename T::a_t;
};
模板
结构获取;
模板
结构获取
{
使用type=typename T::a\u T;
};
我不确定这在你的情况下是否可行。只要A需要存储AB
或AB::A_t
,您就需要B
。不过,引用和指针也可以。您使用的是哪种编译器?我尝试了clang 3.6.1和gcc 4.8.2…“它不工作”。请详细说明你的意思。你的意思是它不再编译了吗?或者你的意思是它没有像你希望的那样减少编译时间?我更新了这个问题。“it not work”(它不工作)的意思是,如果源文件,比如说main.cpp
,只包含a.hpp
但不包含b.hpp
然后main.cpp
不编译,因为类型b
不完整。您是否建议我将extern模板类a
从a.hpp
移动到main.cpp
,其中包括a.hpp
之前的b.hpp
模板类?是的,你必须把它从那里移走。这取决于谁使用模板。将它放在该文件中,模板将不会重新编译,因为您显式地告诉编译器该类可用并在另一个翻译单元中编译。您必须在另一个文件中显式地实例化该模板,例如,为了引用该标准,您需要大量地实例化该模板。你的元函数解决方案在我的情况下是不可行的;这会使事情变得太复杂。对于我的问题,似乎没有一个很好的解决方案,所以停止使用显式模板实例来处理我上面描述的情况。这会增加编译时间,但会导致更干净的include层次结构。