三元运算符决定调用哪个成员函数

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);
}

但是你必须重复接收者和参数。想象一下 thisThingmyStuff 是更复杂表达式的占位符。您可能希望首先将它们放在局部变量中,但这对复制有影响,如果您有很多参数,它就不会很好地发挥作用。

您也许可以将函数指针指向那些成员函数,然后执行类似 (b ? pointerToFoo : pointerToBar)(myStuff); 的操作,但处理函数指针往往很混乱(想想函数重载),而且看起来不像是编译器会适当地优化掉。但我很高兴在这里被证明是错误的。

你可以使用成员函数指针,但是你需要特殊的语法来通过指针调用函数:

struct X {
    void foo() {}
    void bar() {}
};

int main() {
    X thisThing;
    bool b = false;
    (thisThing.*(b ? &X::foo : &X::bar))();
}

但是,我不建议像这样实际使用它(除非有问题中未显示的原因)。请注意,当 foobar 过载时,它不会像这样工作。

无论如何,我认为您的其他示例也不适合条件运算符 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);
}

但是,就像原来的答案一样,如果包含函数重载,则不能使用它。