c++ - GCC 7中模板类的模板成员函数的特化
问题描述
我无法使用 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{};
}
}
为了使它与 GCC 一起编译,我将 ToString 移到了类之外,但它仍然无法编译。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)
在这里在线查看。
解决方案
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
给 this helper()
,让它用它做一些事情,或者用它来调用调用类的方法。
然后,正如我所说,希望您的编译器摆脱这种额外的间接级别,可能会在inline
各处散布一些关键字来鼓励它,或者使用蛮力并使用编译器的扩展来强制它内联所有内容。
用 gcc 8 测试。
推荐阅读
- python - Python:下载基于名称和日期的 s3 文件
- javascript - 使用 onclick 功能忽略阻止默认值
- javascript - 高阶函数中count++和count+1的区别
- python - 使用 Pandas 读取变量列标题时出现问题
- ios - 如何在 UICollectionView 的单元格上使用 TouchDragEnter?
- ios - 在 Objective-C 中设置一个类的值的问题
- javascript - 将javascript对象键与输入值进行比较
- c# - Set style with eventsetter in resources programmatically
- youtube - 从 Youtube 直播视频中获取当前延迟
- django - apache + mod_wsgi restart 保持活动任务