template specialization, different behavior on win

2019-06-07 16:24发布

问题:

I'm looking for an overview or description of what GCC does differently than MSVC for compile + link of template classes with specializations. For example, this type of thing works on GCC but not MSVC:

// Base.h
template <typename T> struct Base {
    template <class G>  QString  makeTitle(const G* obj){obj->CompilerError();}
    };

// in Foo.cpp
template <> template <class G> QString Base<T_1>::makeTitle(const G* obj) {  return mystr(); }
void SomeFunc() {
  std::cout<<  Base<T_1>().makeTitle<myclass>() ;
}

and the solution tends to be that I must declare the specialization in Base.h before using it, or on windows there is a link error. How/why does MSVC implicitly instantiate differently, and how/why is GCC robust to the specialization being declared in some cpp file?

related question that notes the general 'declare before using' requirement: Template specialization - different behaviour between MSVC and GCC/MinGW

回答1:

The first thing is that your code is in violation of the ODR rule if any translation unit includes the header and causes the definition of the specialization without the compiler seeing a declaration. Since that is undefined behavior the fact that one compiler accepts it and the other rejects it is well within reason.

The correct code, as you already figured out is to provide the declaration of the specialization, and that will work in any compiler.

As of why it seems to work or even why does it actually work in gcc, this is most probably a matter of how the code is generated and the linker processes the object files. In particular in gcc the compiler will generate the specialization in the translation unit that needs it (and does not see your own specialization), but it will be marked as a weak symbol. The gcc linker will accept a symbol being multiply defined if all but [at most] one definitions are weak, leaving the strong symbol in the final executable.