extern template & incomplete types

a 夏天 提交于 2021-02-08 14:19:27

问题


Recently when I was trying to optimize my include hierarchy I stumbled upon the file 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.

My goal would have been to define A<B> in a.cpp:

#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. However it does not work (a.hpp on itself doesn't compile!) Is there a better way of doing this?

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!


回答1:


From 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.

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. In the given case, you could remove the using t declaration and have a meta function to yield that type:

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. References and pointers would be OK, though.




回答2:


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. I'm afraid that hiding B's body from users of A<B> is not possible.

extern template is an optimization, but it doesn't change the fundamental workings of the instantiation mechanism.




回答3:


The final extern template class A is telling the compiler that there is in some compilation unit a declaration of such template specialization. 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. You can do different structures:

one a.hpp with just the class A template.

one b.cpp file with the class B along with its .h file. (is it a template?)

b.cpp includes a.hpp and inside you make an explicite template instantiation template class A; (not with extern).

At this point whenever you need to use that template you can just write

extern template class A;

in your file and link the compiled b.cpp file. If you include the a.hpp file since you still need the template you won't recompile it since you have the extern command.



来源:https://stackoverflow.com/questions/34657294/extern-template-incomplete-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!