简体   繁体   English

extern模板和不完整的类型

[英]extern template & incomplete types

Recently when I was trying to optimize my include hierarchy I stumbled upon the file a.hpp : 最近,当我试图优化我的包含层次结构时,我偶然发现了a.hpp文件:

template<class T>
class A
{
  using t = typename T::a_t;
};

class B;

extern template class A<B>;

which seems to be ill-formed. 这似乎是不正常的。 In fact it seems as if the extern template statement at the end causes an instantiation of A<B> which causes the compiler to complain about an incomplete type. 事实上,似乎最后的extern模板语句导致A<B>的实例化,这导致编译器抱怨不完整的类型。

My goal would have been to define A<B> in a.cpp : 我的目标是在a.cpp定义A<B>

#include <b.hpp>
template class A<B>;

This way I avoid having to include b.hpp from a.hpp which seems like a good idea to reduce compile time. 这样,我避免必须包括b.hppa.hpp这似乎是一个好主意,以减少编译时间。 However it does not work ( a.hpp on itself doesn't compile!) Is there a better way of doing this? 但它不起作用( a.hpp本身不编译!)有更好的方法吗?

Note: Of course I could just not use explicit template instantiation but this is not what I want! 注意:当然我可以不使用显式模板实例化,但这不是我想要的! I would like to "precompile" A<B> to save compilation time if it were used, but if A<B> is not used I don't want to include b.hpp in every file that uses a.hpp ! 我想“预编译” A<B>以节省编译时间,如果它被使用,但如果A<B>不使用我不希望包括b.hpp在使用每一个文件a.hpp

The extern template declaration prevents the instantiation of member function bodies, but it forces the instantiation of the class definition, since the compiler needs that anyway, and the class body needs a full definition of the template argument since it accesses its members. extern模板声明阻止了成员函数体的实例化,但它强制实例化类定义,因为无论如何编译器都需要它,并且类体需要模板参数的完整定义,因为它访问它的成员。 I'm afraid that hiding B's body from users of A<B> is not possible. 我担心将B的身体隐藏在A<B>使用者A<B>是不可能的。

extern template is an optimization, but it doesn't change the fundamental workings of the instantiation mechanism. extern模板是一种优化,但它不会改变实例化机制的基本工作方式。

The final extern template class A is telling the compiler that there is in some compilation unit a declaration of such template specialization. 最后的extern模板类A告诉编译器在某些编译单元中存在这种模板特化的声明。 The compiler goes on and then the linker should complain about not finding the correct class. 编译器继续,然后链接器应该抱怨没有找到正确的类。 It is not ill formed; 它没有生病; it depends on the use case. 这取决于用例。 You can define in a separate cpp file the template A. This will obviously just reduce a bit the compile time if you compile it over and over. 您可以在单独的cpp文件中定义模板A.如果您反复编译它,这显然会减少一点编译时间。 You can do different structures: 你可以做不同的结构:

one a.hpp with just the class A template. 只有A类模板的一个a.hpp。

one b.cpp file with the class B along with its .h file. 一个带有B类的b.cpp文件及其.h文件。 (is it a template?) (它是模板吗?)

b.cpp includes a.hpp and inside you make an explicite template instantiation template class A; b.cpp包含a.hpp,在里面你做一个explicite模板实例化模板类A; (not with extern). (不是外部)。

At this point whenever you need to use that template you can just write 此时,只要您需要使用该模板,您就可以编写

extern template class A; extern模板类A;

in your file and link the compiled b.cpp file. 在您的文件中并链接已编译的b.cpp文件。 If you include the a.hpp file since you still need the template you won't recompile it since you have the extern command. 如果您包含a.hpp文件,因为您仍然需要该模板,因为您有extern命令,所以不会重新编译它。

From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1448.pdf 来自http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1448.pdf

The extern specifier used to declare an explicit instantiation of a class template only suppresses explicit instantiations of definitions of member functions and static data members not previously specialized in the translation unit containing the declaration. 用于声明类模板的显式实例化的extern说明符仅抑制成员函数和静态数据成员的定义的显式实例化,这些成员函数和静态数据成员以前没有专门用于包含声明的转换单元。

Thus, if a definition of B is required in A, you cannot use an extern template without knowledge of B. You could of course try to get rid of that requirement. 因此,如果A中需要B的定义,则不能在不知道B的情况下使用extern template 。您当然可以尝试去除该要求。 In the given case, you could remove the using t declaration and have a meta function to yield that type: 在给定的情况下,您可以删除using t声明并使用meta函数来生成该类型:

template<typename T>
struct get_a_t;

template<typename T>
struct get_a_t<A<T>>
{
   using type = typename T::a_t;
};

Not sure it that is feasible in your case. 不确定它在你的情况下是否可行。 As soon as A needs to store a B or a B::a_t , you need B . 一旦A需要存储BB::a_t ,您需要B References and pointers would be OK, though. 不过,引用和指针都可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM