2016-01-27 4 views
4

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

Я думаю, что обработка GCC с частичными специализациями шаблона шаблона просто сломана. Шаблоны классов более зрелые, но вы должны частично специализировать все это, что раздражает. –

+0

@ T.C. Да, я закончил это, очень раздражающе. Благодарю. – alfC

+1

Сообщается как https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69515 –

ответ

1

Это, как представляется, проблема с 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.


Или также предложил @TC использовать статический член функции вместо статического члена (меньше кода)

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 (a constexpr - дружеская версия std::string), но я получил nge linker.

+1

На этом этапе вы можете просто использовать статическую функцию-член вместо статического элемента данных. (Или используйте 'static constexpr const char *'; оба устраняют необходимость определения вне линии.) –

+0

@ T.C., Хорошая точка. Я добавил это к моему ответу. Это меньше кода. Я не понимаю, почему члены 'const static' не могут быть определены inline (in-class), ведь все четные (нестатические) члены могут быть определены в настоящее время. ('constexpr std :: string' не является возможным). Эта особенность сделала бы статический член более привлекательным. – alfC

Смежные вопросы