我的网络代码使用模板特化来序列化不能简单复制的类型。我定义了一个通用模板
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这样的专业化?
EDIT2:
设法生成SSCCE http://netload.in/dateiz3R4eTVqi3/src.tar.gz.htm 这里的错误是另一种方式,但很好。
EDIT3: 修复了文件大小:http://netload.in/dateixP6iOvc6bD/src.zip.htm
答案 0 :(得分:3)
最小化为:
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(强调我的):
如果是模板,成员模板或类模板的成员 明确专门然后应宣布专业化 在第一次使用该特化之前会导致一个 隐式实例化发生在每个翻译单元中 发生了这种用途;无需诊断。如果是程序 没有为显式专业化提供定义 专业化的使用方式会导致 隐式实例化发生或成员是虚拟成员 功能,程序格式错误,无需诊断。一个 永远不会为显式生成隐式实例化 声明但未定义的特化。
另外,下一段的强制性引用(强调我的):
为函数放置显式特化声明 模板,类模板,类模板的成员函数, 类模板的静态数据成员,类的成员类 模板,类模板的成员枚举,成员类 类模板的模板,类的成员函数模板 模板,类模板成员模板的成员函数, 非模板类的成员模板的成员函数,成员 类模板的成员类的函数模板等 放置类模板的部分特化声明, 非模板类的成员类模板,成员类模板 类模板等可以影响程序是否格式正确 根据显式专业化的相对定位 声明及其在翻译单元中的实例化要点 如上下文所述。 撰写专业时,请 小心它的位置;或者使它编译将是这样的试验 点燃自焚。