Специализация шаблонной переменной (для шаблона шаблонного класса)

Когда я пытаюсь специализировать переменную шаблона для универсального контейнера (например, 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 = "->";

4

Решение

Это похоже на проблему с 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_strconstexprверсия std::string) но я получил странные ошибки компоновщика.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]