gcc does not find template specialization

2019-07-16 01:26发布

问题:

My network code uses template specialization to serialize types that can not simply be copied. I defined a general template

template<typename T> struct TypeHandler

that handles all types that can be transported by a simple memcpy and then I define specializations for all other types. The problem now is that I have a file with multiple such specializations and if I compile the code with Visual Studio everything works fine. But with gcc all template specializations in that file get used with the exception of

template<> struct TypeHandler<uint32_t>

which variable length encodes the integer to save space.

Namespaces are the same for all TypeHandler versions and they are even in the same file. But for some reason gcc decides to use the generalized version and I don't really know why.

EDIT:

It seems that gcc uses the instantiation of TypeHandler from an other project that this one links against but doesnt have a specialization for uint32_t even so it transmits uint32_t fields. GCC doesnt give me any error though. How can i tell gcc to use the specialization like Visual Studio does ?

EDIT2:

managed to generate an SSCCE http://netload.in/dateiz3R4eTVqi3/src.tar.gz.htm the bug here is the other way around but well.

EDIT3: fixed filesize : http://netload.in/dateixP6iOvc6bD/src.zip.htm

回答1:

Minimized to:

test1.cpp:

#include <iostream>
#include <stdint.h>

template<typename T>
struct TypeHandler
{
    void Print() { std::cout << "base" << std::endl; }
};


void test1()
{
    std::cout << "p1" << std::endl;
    TypeHandler<uint32_t>().Print();
}

test2.cpp:

#include <iostream>
#include <stdint.h>

template<typename T>
struct TypeHandler
{
    void Print() { std::cout << "base" << std::endl; }
};

template<>
struct TypeHandler<uint32_t>
{
    void Print() { std::cout << "int" << std::endl; }
};

void test2()
{
    std::cout << "p2" << std::endl;
    TypeHandler<uint32_t>().Print();
}

main.cpp:

void test1();
void test2();
int main(){
    test1();
    test2();
}

On Windows/MinGW 4.8.2, compiling with g++ test1.cpp test2.cpp main.cpp -o test and running produces

p1
base
p2
base

while using g++ test2.cpp test1.cpp main.cpp -o test produces

p1
int
p2
int

This is a straightforward standard violation causing undefined behavior. You can't explicitly specialize the same template in one translation unit but not the other. The explicit specialization is not visible in test1.cpp, causing the compiler to generate an implicit instantiation from the base template. So you get two TypeHandler<uint32_t> specializations, and in this instance it appears that the linker decided to pick the one from the first object file it saw. From §14.7.3 [temp.expl.spec]/p6 of the standard (emphasis mine):

If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.

Also, obligatory quote of the next paragraph (emphasis mine):

The placement of explicit specialization declarations for function templates, class templates, member functions of class templates, static data members of class templates, member classes of class templates, member enumerations of class templates, member class templates of class templates, member function templates of class templates, member functions of member templates of class templates, member functions of member templates of non-template classes, member function templates of member classes of class templates, etc., and the placement of partial specialization declarations of class templates, member class templates of non-template classes, member class templates of class templates, etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.