[英]C++ Change member function definition based on template parameter value
是否可以基于模板参数的值在函数中有条件地编译语句? 例如:
template<typename T, bool chk>
class subject
{
public:
// the ideal case
void doSomething(T new_val)
{
if(chk)
{
if(new_val != val)
//do_something only if new_val is different from val
}
else
{
//do_something even if new_val and val are equal
}
}
//or if that's not possible, if chk = 0 use this method
void doSomething(T new_val)
{
//do_something even if new_val and val are equal
}
// and if chk = 1 use this method
void doSomething(T new_val)
{
if(new_val != val)
//do_something only if new_val is different from val
}
T val;
};
捕获是基于chk的值,我什至都不希望将if(new_val!=val)
语句编译到函数中(因为使用的每个T类型都必须定义!=运算符)。
我猜这种方法的一个缺点是foo<int,0>
和foo<int,1>
是不同的类,因此不可能定义一个不在乎chk是0还是1的函数(比如watch(foo<int>)
)。
我正在查看的应用程序专门是观察者,对于某些类型,我只希望观察者在值实际更改时得到通知,对于其他类型,我希望观察者始终得到通知(对于那些我不希望的类型必须定义!=运算符)。
如果没有两个单独的类,这是否可能?
如果没有两个单独的类,这是否可能?
是的。 如果不想专门化您的类,以避免代码重复,则可以使用以下示例中的sfinae表达式:
#include <type_traits>
#include <iostream>
template<typename T, bool chk>
struct subject {
template<bool trigger = chk>
std::enable_if_t<trigger>
doSomething(T new_val) {
if(new_val != val) {
std::cout << "new_val != val" << std::endl;
} else {
std::cout << "new_val == val" << std::endl;
}
}
template<bool trigger = chk>
std::enable_if_t<not trigger>
doSomething(T new_val) {
std::cout << "who cares?" << std::endl;
}
T val;
};
int main() {
subject<int, true> s1{0};
s1.doSomething(0);
s1.doSomething(1);
subject<int, false> s2{0};
s2.doSomething(0);
s2.doSomething(1);
}
这个想法是在编译时就为doSomething
定义了正确的定义,它取决于模板参数chk
的值。 另一个定义只是简单地按预期丢弃,根本无法使用。
请注意,要使sfinae表达式起作用, trigger
模板参数必须是成员函数模板的实际参数。 这就是为什么您必须这样定义它的原因:
template<bool trigger = chk>
sfinae_expression_based_on_enable_if
doSomething(T new_val) { /* ... */ }
看到它在coliru上运行。
您正在寻找的被称为“模板专业化”。
您将必须专门化您的模板。 在定义了基本模板之后,如上所述,您将继续并定义其专业化:
template<typename T>
class subject<T, true>
{
public:
// ...
然后,对于第二个模板参数为true
(或false
,如果需要专门设置的话),您可以从头开始定义整个subject
类,并进行所需的任何更改。 您可以删除,添加或完全更改它们。 专门的类可以具有不同的类成员,方法或相同的类方法,但是它们的工作方式完全不同。
重要的是要了解您正在定义整个类,而不仅仅是定义不同的位。 如果确实只需要对该类的一个较小方面进行专门化,那么这当然会导致一堆重复的代码; 因此通常需要对其进行重构,将不同的位放入帮助器类或函数中,并仅对不同的位进行专门化处理。
即将到来的C ++ 17标准还提供了一些其他的模板专业化替代方法。 但是在这种情况下,传统上,专业化是第一要学的东西。 因此,在继续学习C ++ 17的新知识之前,您应该将C ++书籍放到讨论模板专业化的章节中,并首先掌握其中的知识。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.