2016-01-27 180 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; 

这个工作在两个gccclang


或者还通过@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_strconstexpr-std::string的友好版本),但我得到了stra nge链接器错误。

+1

此时您不妨使用静态成员函数而不是静态数据成员。 (或者使用'static constexpr const char *';这两个都不需要一个非线性定义。) –

+0

@ T.C。,好点。我在我的回答中加了这个。这是更少的代码。我不明白为什么'const static'成员不能在inline(in-class)中定义,因为现在所有的偶数(非静态)成员都可以定义为内联。 ('constexpr std :: string'不是可能的)。该功能将使静态成员更具吸引力。 – alfC