gcc 找不到模板特化 [英] gcc does not find template specialization

查看:41
本文介绍了gcc 找不到模板特化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的网络代码使用模板特化来序列化不能简单复制的类型.我定义了一个通用模板

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

处理可以通过简单的 memcpy 传输的所有类型,然后我为所有其他类型定义特化.现在的问题是我有一个具有多个此类专业化的文件,如果我使用 Visual Studio 编译代码,一切正常.但是对于 gcc,除了

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.

所有 TypeHandler 版本的命名空间都是相同的,它们甚至在同一个文件中.但是出于某种原因,gcc 决定使用通用版本,我真的不知道为什么.

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.

似乎 gcc 使用了来自另一个项目的 TypeHandler 实例化,该项目与之链接但没有专门针对 uint32_t 的项目,即使它传输 uint32_t 字段.虽然 GCC 没有给我任何错误.我如何告诉 gcc 像 Visual Studio 一样使用专业化?

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 ?

编辑 2:

设法生成了一个 SSCCE http://netload.in/dateiz3R4eTVqi3/src.tar.gz.htm这里的错误是相反的,但很好.

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

固定文件大小: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 编译并运行产生

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

p1
base
p2
base

同时使用 g++ test2.cpp test1.cpp main.cpp -o test 产生

p1
int
p2
int

这是导致未定义行为的直接违反标准.您不能在一个翻译单元中明确特化同一个模板,而不能在另一个翻译单元中明确特化.显式特化在 test1.cpp 中不可见,导致编译器从基本模板生成隐式实例化.所以你得到了两个 TypeHandler 特化,在这个例子中,链接器似乎决定从它看到的第一个目标文件中选择一个.来自标准的 §14.7.3 [temp.expl.spec]/p6(强调我的):

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.

这篇关于gcc 找不到模板特化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆