Когда я пытаюсь специализировать переменную шаблона для универсального контейнера (например, std::list<...>
а не для конкретного, например std::list<double>
) Я получаю ошибку связи с gcc 5.3
(но не с clang 3.5
)
/tmp/ccvxFv3R.s: Assembler messages:
/tmp/ccvxFv3R.s:206: Error: symbol `_ZL9separator' is already defined
http://coliru.stacked-crooked.com/a/38f68c782d385bac
#include<string>
#include<iostream>
#include<list>
#include<forward_list>
#include<vector>
template<typename T> std::string const separator = ", ";
template<typename... Ts> std::string const separator<std::list<Ts...> > = "<->";
template<typename... Ts> std::string const separator<std::forward_list<Ts...>> = "->";
int main(){
std::cout << separator<std::vector<double>> << '\n';
std::cout << separator<std::list<double>> << '\n';
std::cout << separator<std::forward_list<double>> << '\n';
}
(Это хорошо сочетается с clang 3.5
и работает как положено. Кроме того, шаблон variadic — это не то, что вызывает проблему, я пытался использовать шаблон без переменных переменных).
Если это не ошибка в gcc
Как вы думаете, есть ли работа вокруг? Я пытался использовать специализацию класса, но это также невозможно:
template<class T>
struct separator{
static std::string const value;
};
template<class T>
std::string const separator<T>::value = ", ";
template<typename... Ts>
std::string const separator<std::list<Ts...>>::value = "<->";
template<typename... Ts>
std::string const sep<std::forward_list<Ts...>>::value = "->";
Это похоже на проблему с gcc
, Обходной путь (используйте шаблоны классов), например @ T.C. предложил.
template<class T>
struct sep{
static const std::string value;
};
template<class T>
const std::string sep<T>::value = ", ";
template<typename... Ts>
struct sep<std::list<Ts...>>{
static const std::string value;
};
template<typename... Ts>
const std::string sep<std::list<Ts...>>::value = "<->";
template<typename... Ts>
struct sep<std::forward_list<Ts...>>{
static const std::string value;
};
template<typename... Ts>
const std::string sep<std::forward_list<Ts...>>::value = "->";
А потом переменная шаблона (чтобы иметь такой же интерфейс)
template<typename T> std::string const separator = sep<T>::value;
Это работает в обоих gcc
а также clang
,
Или также предложено @ T.C., Использовать статический член функции вместо статического члена (меньше кода)
template<class T>
struct sep{
static std::string value(){return ", ";}
};
template<typename... Ts>
struct sep<std::list<Ts...>>{
static std::string value(){return "<->";}
};
template<typename... Ts>
struct sep<std::forward_list<Ts...>>{
static std::string value(){return "->";}
};
...
template<typename T> std::string const separator = sep<T>::value();
Или использовать constexpr const char*
template<class T>
struct sep{static constexpr const char* value = ", ";};
template<typename... Ts>
struct sep<std::list<Ts...>>{static constexpr const char* value = "<->";};
template<typename... Ts>
struct sep<std::forward_list<Ts...>>{static constexpr const char* value = "->";};
...
template<typename T> std::string const separator = sep<T>::value;
Я пытался использовать const_str
(а constexpr
версия std::string
) но я получил странные ошибки компоновщика.
Других решений пока нет …