是否可以将纯右值显式转换为 const 引用以避免三元运算符中的额外复制?

Ale*_*ous 6 c++ conditional-operator prvalue

假设我们有一些不可复制和不可移动的类型Foo,以及一个函数

int f(const Foo& foo) {
  ... // somehow compute the result depending on the value of foo.
}
Run Code Online (Sandbox Code Playgroud)

现在假设我们想像这样调用这个函数:

const Foo foo1{ 42 };
bool condition = getCondition();
int result = f(condition ? foo : Foo{ 150 });
Run Code Online (Sandbox Code Playgroud)

这不会编译,因为fooFoo{ 150 }属于不同的值类别,因此,根据定义,三元运算符将返回类型的纯右值Foo- 这意味着foo1需要复制 if condition == true,因此这会导致编译错误。

然而,C++ 保证临时对象在表达式结束之前保持有效,因此我们可以这样写:

const Foo foo1{ 42 };
bool condition = getCondition();
int result = f(condition ? foo1 : static_cast<const Foo&>(Foo{ 150 });
Run Code Online (Sandbox Code Playgroud)

现在三元运算符返回const Foo&,即使此引用引用Foo{ 150 },这个临时对象也将保持有效,直到表达式结束。没有发生复制/移动,因此可以编译。

显然,更安全的选择是只写:

int result = condition ? f(foo1) : f(Foo{ 150 });
Run Code Online (Sandbox Code Playgroud)

然而,如果有额外的参数,这可能会导致大量的样板文件,并且对于多个“条件”参数呈指数增长:

int result = condition1
               ? (condition2 ? f(foo1, foo2) : f(foo1, Foo{ 222 }))
               : (condition2 ? f(Foo{ 111 }, foo2) : f(Foo{ 111 }, Foo{ 222 }));
Run Code Online (Sandbox Code Playgroud)

上面的 hack 允许更短的形式:

int result = f( condition1 ? foo1 : static_cast<const Foo&>(Foo{ 111 }),
                condition2 ? foo2 : static_cast<const Foo&>(Foo{ 222 }) );
Run Code Online (Sandbox Code Playgroud)

我知道这有点危险,但我认为上面的代码有效吗?

PS我还想知道当有N个这样的“条件”参数时,编译器是否生成O(N)或O(2^N)指令。

三元运算符和通过引用 const 延长临时对象的生命周期解决了类似的情况,但问题是三元运算符本身是否延长了临时对象的生命周期 - 它不会。