4

考虑以下代码(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 作为模板参数的引用仅声明为 extern,则将其视为未标记。并且在定义后被视为标记。

我项目中的某些类被实例化了两次,而应该只有一个类。这是相当不愉快的。

gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2)

它是编译器中的错误吗?还是预期的行为?有什么办法可以解决?

4

1 回答 1

2

这绝对是一个编译器错误;我在 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

于 2016-02-02T11:12:26.683 回答