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)
这不会编译,因为foo和Foo{ 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 延长临时对象的生命周期解决了类似的情况,但问题是三元运算符本身是否延长了临时对象的生命周期 - 它不会。