4

首先,我有一个类的头文件,一个没有定义的专业化声明(来自互联网的代码示例)

$猫foo.h

template<typename T>
class foo{
public:
  static void init(){
      return;
  }

};

template<>  void foo<int>::init();

然后有2个模板专业化的实现文件

$ cat foo_int.cpp 
#include "foo.h"
#include<stdio.h>
template<>
void foo<int>::init(){
    printf("init int foo\n");
}

$ cat foo_float.cpp 
#include "foo.h"
#include<stdio.h>
template<>
void foo<float>::init(){
    printf("init float foo\n");
}

最后我得到了一个主文件

$ cat main.cpp
#include "foo.h"

int main(){
  foo<int>::init();
  foo<float>::init();
}

如果我在没有优化的情况下编译它并运行它,它会给出:

g++ foo_int.cpp foo_float.cpp main.cpp && a.out
init int foo
init float foo

如果我添加优化,那么结果会有所不同:

$ g++ foo_int.cpp foo_float.cpp main.cpp -O2 && a.out
init int foo

结果是不同的。来自互联网的一些解释说这是由于gcc实现中“弱符号”的一些内部机制,但我的问题是:

  1. “弱符号”/“强符号”是 gcc/g++ 的概念,还是 c/c++ 语言规范的一部分。

  2. 如果调试和发布结果不同,关于“弱符号”机制,我应该说这是 gcc/g++ 的错误/问题吗?作为开发人员,我不希望我的调试版本的行为与发布版本不同。

我试过clang,不幸的是同样的错误。对于调试/发布“应该”表现如此不同的 C/C++,这是一个“可接受的”案例吗?

4

2 回答 2

6

语言定义要求您在使用之前声明显式特化:

如果模板、成员模板或类模板的成员被显式特化,则应在第一次使用该特化之前声明该特化,这将导致隐式实例化发生,在每个翻译单元中出现这种使用; 不需要诊断。[温度.expl.spec]/6。

foo<float>::init()在从 调用它的地方没有显式特化 of 的声明main,但是在 中有一个显式特foo_float.cpp化,因此程序的行为是未定义的。

于 2016-10-11T11:46:17.557 回答
4

你违反了一个定义规则——你的程序包含两个foo<float>::init.

一个定义出现在编译单元foo_float.cpp中,另一个出现在编译单元main.cpp中。

违反一个定义规则意味着未定义的行为——在这种情况下,可能发生的情况是:

  • 在关闭优化的情况下,程序会生成一个实际的函数调用,并且链接器碰巧将foo_float.cpp函数的版本放入可执行文件中。
  • 启用优化后,编译main.cpp器在编译时内联函数 - 自然,它会内联main.cpp函数的版本。
于 2016-10-11T11:37:17.627 回答