我的网络代码使用模板专门化来序列化不能简单复制的类型。我定义了一个通用模板
template<typename T> struct TypeHandler
处理可以通过简单的memcpy传输的所有类型,然后我为所有其他类型定义专门化。现在的问题是我有一个包含多个此类特化的文件,如果我使用 Visual Studio 编译代码,一切都会正常工作。但是对于 gcc,该文件中的所有模板特化都会被使用,除了
template<> struct TypeHandler<uint32_t>
哪个可变长度对整数进行编码以节省空间。
所有 TypeHandler 版本的命名空间都是相同的,甚至位于同一个文件中。但由于某种原因,gcc 决定使用通用版本,我真的不知道为什么。
编辑:
看起来 gcc 使用了另一个项目中 TypeHandler 的实例化,该项目链接到该项目,但没有 uint32_t 的专门化,即使它传输 uint32_t 字段。不过,GCC 没有给我任何错误。我如何告诉 gcc 使用 Visual Studio 那样的特化?
编辑2:
成功生成 SSCCE http://netload.in/dateiz3R4eTVqi3/src.tar.gz.htm 这里的错误是相反的,但是很好。
编辑3: 固定文件大小:http://netload.in/dateixP6iOvc6bD/src.zip.htm
最佳答案
最小化为:
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();
}
在 Windows/MinGW 4.8.2 上,使用 g++ test1.cpp test2.cpp main.cpp -o test
进行编译运行产生
p1
base
p2
base
使用g++ test2.cpp test1.cpp main.cpp -o test
时产生
p1
int
p2
int
这是一种直接违反标准的行为,会导致未定义的行为。您不能在一个翻译单元中显式地专门化相同的模板,而在另一个翻译单元中则不能。显式特化在 test1.cpp
中不可见,导致编译器从基本模板生成隐式实例化。所以你得到两个TypeHandler<uint32_t>
特化,在这种情况下,链接器似乎决定从它看到的第一个目标文件中选择一个。来自标准的 §14.7.3 [temp.expl.spec]/p6(强调我的):
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.
此外,必须引用下一段(强调我的):
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.
关于c++ - gcc 找不到模板专门化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24678735/