std::string & 在 gcc 5 中作为模板参数和 abi_tag

std::string & as template parameter and abi_tag in gcc 5

考虑以下代码 (test1.cpp):

#include <string>

extern std::string test_string;

template<std::string &s>
class test{
public:
   static void bar(){ }
};

std::string test_string("test string");
void foo(){test<test_string>::bar();}

现在让我们调换最后两行代码的顺序(test2.cpp):

#include <string>

extern std::string test_string;

template<std::string &s>
class test{
public:
   static void bar(){ }
};

void foo(){test<test_string>::bar();}
std::string test_string("test string");

什么都不应该改变。但是如果你通过 objdump 查看编译后的文件,你会看到不同之处:

objdump -t -C test*.o | grep bar

在一种情况下,模板测试实例化为:

test<test_string[abi:cxx11]>::bar()

在另一个中为:

test<test_string>::bar()

两个文件都是用

编译的
gcc -c test*.cpp

因此,如果将 std::string 引用为模板参数,则如果它只是声明为外部,则将被视为未标记。并且它在定义后被视为标记。

我项目中的一些 class 被实例化了两次,而应该只有一个 class。比较不爽。

gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2)

是不是编译器的bug?或者这是预期的行为? 有什么解决方法?

这绝对是一个编译器错误;我无法在 GCC Bugzilla 中找到确切的错误,但它看起来类似于 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66971 - 尽管更简单,因为它不需要使用 thread_local 关键字,它很可能具有相同的根本原因。

作为变通方法,将引用模板参数更改为指针似乎可以使它起作用:

template<std::string *s> class test { .... };
void foo(){test<&test_string>::bar();}

编辑:我已将此错误提交给 gcc https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69621