我无法使用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。
ToString
是另一个模板类的模板成员。
首先,如果不专门设计外部模板,则无法专门构建内部模板。也就是说,你必须首先专门化一些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测试。
您在类模板中定义了函数模板时缺少一个template
关键字。这应该工作:
template<class C>
template<>
typename BasicScalarFormatter<C>::String BasicScalarFormatter<C>::ToString<bool>(bool val)
{
return String{};
}
当您使用模板参数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