考虑以下代码:
template<typename T, SomeEnum mode> struct TC{
T data;
//...
void doStuff();
};
“doStuff”可以根据为模板设置的枚举值有多个定义吗?
TC<int, SomeEnum::MODE_1> tc1; tc.doStuff(); //do some stuff
TC<int, SomeEnum::MODE_2> tc2; tc.doStuff(); //do some other stuff
(我不是指保存“模式”并在其上创建一个分支,但实际上是多个定义。)
答案 0 :(得分:4)
你可以做标签调度。只需为枚举的每个打包值提供重载:
template<typename T, SomeEnum mode> struct TC{
T data;
//...
template<SomeEnum v>
using tag_type = std::integral_constant<SomeEnum, v>;
void reallyDoStuff(tag_type<SomeEnum::MODE_1>);
void reallyDoStuff(tag_type<SomeEnum::MODE_2>);
void doStuff() { reallyDoStuff(tag_type<mode>{}); }
};
由于类模板的成员函数除非被使用,否则不会被实例化,因此您只需为reallyDoStuff
的每个实例实例化TC
(正确的一个)的一个定义
如果有疑问,请选择函数模板重载到专门化。它通常是最好的选择。
答案 1 :(得分:0)
通常,这是模板专业化的用途。如果你不知道什么是模板专业,你需要先阅读你的C ++书籍,然后再阅读我的答案。
这里唯一的绊脚石是单个类方法不能专门化,整个类必须是专用的。但是有一些常见的方法,例如以下内容。
将您的成员函数定义为辅助模板类的函数调用包装器,如下所示:
template<typename T, SomeEnum mode> void TC::doStuff()
{
doStuff_helper<T, mode>::doStuff(*this);
}
那是你真正的doStuff()。实际代码进入辅助类。 定义帮助程序类模板如下(当然,您需要正确使用前向声明和其他此类杂项):
template<typename T, SomeEnum mode> class doStuff_helper {
public:
static void doStuff(TC<T, mode> &me)
{
// ...
}
};
原始类方法所做的一切现在都可以在这里完成,但有一些明显的区别。这不是原始类的实际方法了。因此,您可以使用this
引用而不是原始me
。并且因为这不是实际的类方法,所以访问私有或受保护的类成员会遇到常见问题。但这些是根据自身优点轻松解决的细微问题。关键是你现在能做的就是专注于整个事情:
template<typename T> class doStuff_helper<T, MODE_VALUE> {
public:
static void doStuff(TC<T, MODE_VALUE> &me)
{
// ...
}
};
这doStuff()
现在可以完全不同了。这是将不允许的类方法专业化转换为普通的,花园种类,类专业化的一般方法。
对这种常用方法有进一步的改进,经常使用。一个这样的改进就是将这个因素考虑在内doStuff()
本身只不过是对me
的包装和方法调用,一般和专用版本在原始模板类中调用不同的方法。 / p>
一旦你用一张纸和一支铅笔弄清楚这里发生了什么,你会发现它最终做的是将一个调用转到原来的doStuff()
类方法来调用两个不同的类方法(通常为private
),具体取决于原始模板类的参数。这两个不同的类方法基本上是您最初想要拥有的两个不同版本的doStuff()
,只使用适当的方法,具体取决于模板参数。