Рассмотрим следующий фрагмент кода (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)
Это ошибка в компиляторе? Или это ожидаемое поведение?
Какой может быть обходной путь?
Это определенно ошибка компилятора; Я не могу найти точную ошибку в 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
Других решений пока нет …