当链接器可以显式特化时,是否所有编译器都忽略生成的模板代码?

do all compilers ignore generated template code when explicit specializations are available to the linker?

本文关键字:编译器 代码 链接 是否      更新时间:2023-10-16

我最近在专门化模板时遇到了一种让我感到不安的情况:

foo:

template <class T>
void foo() {
  std::cout << "This is the generic foo" << std::endl;
}

foo.cc:

#include "foo.h"
template <>
void foo<int>() {
  std::cout << "This is foo<int>" << std::endl;
}

main.cc:

#include "foo.h"
int main() {
  foo<int>();
}

。我编译如下:

g++ -c main.cc
g++ -c foo.cc
g++ -o main main.o foo.o

输出为"This is foo<int>"。我喜欢这个输出。但是我担心我观察到的可能是gcc独有的(我没有访问其他编译器的权限,所以我无法检查)。

我认为gcc正在做的是:cc被编译,我希望它发出foo调用的泛型代码,因为它不知道foo.cc中的专门化。但是通过与foo连接。O,它使用专门化,因为它具有相同的签名。

但是指望这个不好吗?我担心其他编译器(甚至可能是不同版本的gcc?)在发出模板代码时可能会弄乱它们的签名,以一种与foo链接的方式。o不会像我希望的那样替换通用动作。这种担心合理吗?我读过很多让我感到不安的东西,但没有什么能让我对目前的情况感到自信。

我担心我观察到的可能是gcc独有的(我没有访问其他编译器的权限,所以我无法检查)。

你有充分的理由担心:你的程序是病态的,编译器甚至不需要告诉你!

c++ 11标准第14.7.3/6段规定:

如果模板、成员模板或类模板的成员显式特化,则该特化应该在第一次使用可能导致隐式实例化的专门化之前声明发生:在发生这种用法的每个翻译单元中发生;不需要诊断。如果程序没有为显式专门化提供定义,或者以某种方式使用专门化会导致隐式实例化发生,或者成员是虚成员函数,程序格式错误,不需要诊断。永远不会为显式实例生成隐式实例已声明但未定义的专门化

为了使程序具有一致的行为,您的专门化必须从实例化的角度可见。在您的情况下,它不是:您将它降级到其他翻译单元不包含的文件中。

第14.7.3/7段对于不这样做会发生什么非常明确:

函数模板、类模板、成员函数的显式特化声明的位置对于类模板,[…]],可以影响一个程序是否被根据显式专门化声明及其点的相对定位而形成的在上面和下面指定的翻译单元中实例化。在编写专门化时要小心关于其位置;或者让它编译将是一种考验,从而点燃它的自焚。

我想最后一句已经说得很清楚了。

在这里,你应该做的是在出现主模板的任何隐式实例化之前声明你想要引入函数模板的显式专门化。为此,请执行以下操作:

foo。

template <class T>
void foo() {
   std::cout << "This is the generic foo" << std::endl;
}
template <> void foo<int>(); // Introduce a declaration of your
                             // explicit specialization right
                             // after you defined the primary
                             // template!

通过在主模板定义之后引入声明,可以确保无论主模板在哪里可见,都知道它存在完整的专门化,从而避免了自我牺牲。