local lvalue references-to-const and rvalue references can extend the lifetime of temporaries:
const std::string& a = std::string("hello");
std::string&& b = std::string("world");
Does that also work when the initializer is not a simple expression, but uses the conditional operator?
std::string&& c = condition ? std::string("hello") : std::string("world");
What if one of the results is a temporary object, but the other one isn't?
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");
Does C++ mandate the lifetime of the temporary be extended when the condition is false?
The question came up while answering this question about non-copyable objects.
SystemVerilog. The conditional operator ?: chooses, based on a first expression, between a second and third expression. The first expression is called the condition. If the condition is 1, the operator chooses the second expression.
There are three conditional operators: && the logical AND operator. || the logical OR operator. ?: the ternary operator.
The conditional operator (? :) is a ternary operator (it takes three operands). The conditional operator works as follows: The first operand is implicitly converted to bool . It is evaluated and all side effects are completed before continuing.
The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.
Both of those are fine.
§5.16 says (extraordinarily abridged):
2 If either the second or the third operand has type void
Nope.
3 Otherwise, if the second and third operand have different types
Nope.
4 If the second and third operands are glvalues of the same value category
Nope. (In the first, both are prvalues and in the second one is a glvalue and one is a prvalue.)
5 Otherwise, the result is a prvalue
Okay, so both of these result in prvalues. So the binding is fine, but what's the binding to?
6 Lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are per- formed on the second and third operands.
Okay, so both are now rvalues if they weren't already.
6 (continued) After those conversions, one of the following shall hold:
The second and third operands have the same type; the result is of that type. If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.
Okay, so it's either std::string(first_operand)
or std::string(second_operand)
.
Regardless, the result of the conditional expression is a new prvalue temporary, and it's that value that's extended by binding to your references.
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");
Does C++ mandate the lifetime of the temporary be extended when the condition is false?
It will be. The conditional is an rvalue expression, and when bound with a const
reference the compiler will create an unnamed object and bind the reference to it. What I am not 100% sure is whether the temporary whose lifetime is extended is std::string("world")
or whether a copy of it is (conceptually) made (and elided).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With