我无法使用GCC 7.3编译以下代码:
template <class C>
class BasicScalarFormatter
{
public:
typedef std::basic_string<C> String;
template<typename T>
static String ToString(T val)
{
return String{};
}
};
template<class C>
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
{
return String{};
}
怎么了?
在VC2017中,如果在类内定义了ToString,它将编译:
template <class C>
class BasicScalarFormatter
{
public:
typedef std::basic_string<C> String;
template<typename T>
static String ToString(T val)
{
return ToBasicString<C, T>(val);
}
template<>
static String ToString(bool val)
{
return String{};
}
}
到make it compile with GCC I moved ToString outside of the class,但仍然无法编译。 GCC错误消息是:
ource_file.cpp:21:98: error: template-id ‘ToString<bool>’ in declaration of primary template
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
^
source_file.cpp:21:50: error: prototype for ‘BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString(bool)’ does not match any in class ‘BasicScalarFormatter<C>’
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
^
source_file.cpp:14:27: error: candidate is: template<class C> template<class T> static BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString(T)
static String ToString(T val)
online here看到它。
答案 0 :(得分:3)
ToString
是另一个模板类的模板成员。
如果不对外部模板 first 进行特殊化,就不能对内部模板进行特殊化。也就是说,您必须先对BasicScalarFormatter
的某些特定实例进行特殊化,然后采用该特殊实例,然后才能对其成员模板方法的特定实例进行特殊化。但是,该专门化当然仅适用于专门化的BasicScalarFormatter
。
您的明显意图是不对外部模板类的所有实例进行专门化,而是对该类成员进行专门化。
这里没有真正干净的解决方案,但是这种通用设计模式通常足够简单,以至于智能编译器最终都会优化掉额外的重定向:
#include <string>
template<typename C, typename T> class ToStringHelper {
public:
static std::basic_string<C> helper()
{
return std::basic_string<C>();
}
};
template<typename C> class ToStringHelper<C, bool> {
public:
static std::basic_string<C> helper()
{
return std::basic_string<C>();
}
};
template <class C>
class BasicScalarFormatter
{
public:
typedef std::basic_string<C> String;
template<typename T>
static String ToString(T val)
{
return ToStringHelper<C,T>::helper();
}
};
void foo()
{
BasicScalarFormatter<char> c;
c.ToString(0);
c.ToString(true);
}
因此,在这一点上,您进入了助手类的静态方法。您最终的目标显然是使用原始模板的成员。好吧,您始终可以将this
传递给此helper()
,并使其执行某些操作,或使用它来调用调用类的方法。
然后,就像我说的那样,希望您的编译器摆脱这种额外的间接访问级别,也许是在各处散布一些inline
关键字来鼓励它,或者使用蛮力并使用编译器的扩展以强制其内联所有内容。
经过gcc 8测试。
答案 1 :(得分:0)
在类模板中定义函数模板时,缺少一个template
关键字。这应该起作用:
template<class C>
template<>
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
{
return String{};
}
答案 2 :(得分:0)
在实现带有模板参数template <typename C>
的类的方法时,缺少C
。
尝试这样:
#include <string>
template <class C>
class BasicScalarFormatter
{
public:
typedef std::basic_string<C> String;
template<typename T>
static String ToString(T val);
};
template <typename C>
template <typename T>
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::
ToString(T val)
{
return String{};
}
应使用GCC 7.3
进行编译,请参见here