我的模板专业化将调试版本与发布版本不同,这是 gcc 错误吗?

My template specialization differs debug version from release version, is this gcc bug?

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

$猫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. Is "weak symbol"/"strong symbol" a concept of gcc/g++, or it's part of the c/c++ language specification.

  2. If debug and release results are different, should I say this is a bug/issue of gcc/g++, in regard with "weak symbol" mechanism? As a developer, I wouldn't expect my debug version to behave differently from release version.

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

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

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

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

  • 关闭优化后,程序会生成一个实际的函数调用,链接器恰好将 foo_float.cpp 版本的函数放入可执行文件中。
  • 启用优化后,在编译 main.cpp 时,编译器会内联该函数 — 自然地,它会内联 main.cpp 的函数版本。

语言定义要求您在使用前声明一个明确的特化:

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. [temp.expl.spec]/6.

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