三元运算符决定调用哪个成员函数
Decide which member function to call by ternary operator
如果我想在对象 thisThing
上调用函数 foo
(在 C# 行话中,这称为“接收器”,所以我在这里也称它为)并传递参数 myStuff
,我会这样做:
thisThing.foo(myStuff);
超级简单,没什么奇怪的。
如果布尔值 b
为假,我想将参数更改为 yourStuff
,我会这样做:
thisThing.foo(b ? myStuff : yourStuff);
也很简单,三目运算符的基本使用。
如果 b
为假,我想将接收器更改为 otherThing
,我会这样做:
(b ? thisThing : otherThing).foo(myStuff);
有点奇怪,你可能不会经常这样做,但这也没什么疯狂的。
但是如果 b
为假,我想将调用的函数更改为 bar
,我该怎么做?
我会这样想:
thisThing.(b ? foo : bar)(myStuff);
但是,当然,这是行不通的。
是否有一种简单、美观、高效的方法来执行此操作,最好不要多余地指定任何内容?
可能必须做出一些妥协,但重点是不必重复接收者和参数。所以以下工作:
if (b)
{
thisThing.foo(myStuff);
}
else
{
thisThing.bar(myStuff);
}
但是你必须重复接收者和参数。想象一下 thisThing
和 myStuff
是更复杂表达式的占位符。您可能希望首先将它们放在局部变量中,但这对复制有影响,如果您有很多参数,它就不会很好地发挥作用。
您也许可以将函数指针指向那些成员函数,然后执行类似 (b ? pointerToFoo : pointerToBar)(myStuff);
的操作,但处理函数指针往往很混乱(想想函数重载),而且看起来不像是编译器会适当地优化掉。但我很高兴在这里被证明是错误的。
你可以使用成员函数指针,但是你需要特殊的语法来通过指针调用函数:
struct X {
void foo() {}
void bar() {}
};
int main() {
X thisThing;
bool b = false;
(thisThing.*(b ? &X::foo : &X::bar))();
}
但是,我不建议像这样实际使用它(除非有问题中未显示的原因)。请注意,当 foo
或 bar
过载时,它不会像这样工作。
无论如何,我认为您的其他示例也不适合条件运算符 use-cases。条件运算符不仅仅是 if-else 的等价替代品。它略有不同 use-cases。有时使用条件运算符来确定两个表达式的公共类型。有时您不能使用 if-else。例如初始化引用时:
int& x = a ? c : d; // cannot be done with if/else
我的建议是:与 if-else 相比,不要使用条件运算符来节省输入时间。 if-else 和条件运算符之间的区别几乎不在于您必须编写的代码量。
怎么样:
thisThing.foo_or_bar(b, myStuff);
和:
ThingClass::foo_or_bar(bool b, SomeType myStuff)
{
if (b)
foo(myStuff);
else
bar(myStuff);
}
类似于 @463035818_is_not_a_number 的回答,但不是使用指向成员运算符 (.*
) 的指针和所有括号,我会使用 std::invoke
代替:
struct X {
void foo() {}
void bar() {}
};
int main() {
X thisThing;
bool b = false;
std::invoke(b ? &X::foo : &X::bar, thisThing);
}
但是,就像原来的答案一样,如果包含函数重载,则不能使用它。
如果我想在对象 thisThing
上调用函数 foo
(在 C# 行话中,这称为“接收器”,所以我在这里也称它为)并传递参数 myStuff
,我会这样做:
thisThing.foo(myStuff);
超级简单,没什么奇怪的。
如果布尔值 b
为假,我想将参数更改为 yourStuff
,我会这样做:
thisThing.foo(b ? myStuff : yourStuff);
也很简单,三目运算符的基本使用。
如果 b
为假,我想将接收器更改为 otherThing
,我会这样做:
(b ? thisThing : otherThing).foo(myStuff);
有点奇怪,你可能不会经常这样做,但这也没什么疯狂的。
但是如果 b
为假,我想将调用的函数更改为 bar
,我该怎么做?
我会这样想:
thisThing.(b ? foo : bar)(myStuff);
但是,当然,这是行不通的。
是否有一种简单、美观、高效的方法来执行此操作,最好不要多余地指定任何内容?
可能必须做出一些妥协,但重点是不必重复接收者和参数。所以以下工作:
if (b)
{
thisThing.foo(myStuff);
}
else
{
thisThing.bar(myStuff);
}
但是你必须重复接收者和参数。想象一下 thisThing
和 myStuff
是更复杂表达式的占位符。您可能希望首先将它们放在局部变量中,但这对复制有影响,如果您有很多参数,它就不会很好地发挥作用。
您也许可以将函数指针指向那些成员函数,然后执行类似 (b ? pointerToFoo : pointerToBar)(myStuff);
的操作,但处理函数指针往往很混乱(想想函数重载),而且看起来不像是编译器会适当地优化掉。但我很高兴在这里被证明是错误的。
你可以使用成员函数指针,但是你需要特殊的语法来通过指针调用函数:
struct X {
void foo() {}
void bar() {}
};
int main() {
X thisThing;
bool b = false;
(thisThing.*(b ? &X::foo : &X::bar))();
}
但是,我不建议像这样实际使用它(除非有问题中未显示的原因)。请注意,当 foo
或 bar
过载时,它不会像这样工作。
无论如何,我认为您的其他示例也不适合条件运算符 use-cases。条件运算符不仅仅是 if-else 的等价替代品。它略有不同 use-cases。有时使用条件运算符来确定两个表达式的公共类型。有时您不能使用 if-else。例如初始化引用时:
int& x = a ? c : d; // cannot be done with if/else
我的建议是:与 if-else 相比,不要使用条件运算符来节省输入时间。 if-else 和条件运算符之间的区别几乎不在于您必须编写的代码量。
怎么样:
thisThing.foo_or_bar(b, myStuff);
和:
ThingClass::foo_or_bar(bool b, SomeType myStuff)
{
if (b)
foo(myStuff);
else
bar(myStuff);
}
类似于 @463035818_is_not_a_number 的回答,但不是使用指向成员运算符 (.*
) 的指针和所有括号,我会使用 std::invoke
代替:
struct X {
void foo() {}
void bar() {}
};
int main() {
X thisThing;
bool b = false;
std::invoke(b ? &X::foo : &X::bar, thisThing);
}
但是,就像原来的答案一样,如果包含函数重载,则不能使用它。