Reputation: 19642
Consider:
struct A { bool operator==(const A& that) { return true; } };
boost::optional<A&> f()
{
std::vector<A> vec;
auto it = std::find(vec.begin(), vec.end(), A());
// Version A
return (it == vec.end() ? nullptr : *it);
// Version B
if (it == vec.end()) {
return nullptr;
} else {
return *it;
}
}
Why does version A not compile (error C2446: ':' : no conversion from 'A' to 'nullptr') while version B does?
(I know that I can do e.g.
return (it == vec.end() ? boost::optional<A&>() : *it);
, my question is: why is construction from nullptr apparently treated differently from with the ternary operator?)
Only tested on msvc12 (=Visual Studio 2013).
Upvotes: 5
Views: 2137
Reputation: 55897
Rules for ternary operator from standard 5.16
if the second and third operand have different types and either has (possibly cv-qualified) class type, or if both are glvalues of the same value category and the same type except for cv-qualification, an attempt is made to convert each of those operands to the type of the other.
...
Otherwise (if E1 or E2 has a non-class type, or if they both have class types but the underlying classes are not the same and neither is a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted to the type that E2 would have after applying the lvalue-to- rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions.
A
is not implicitly convertible to nullptr
and nullptr
is not implicitly convertible to A
.
Second version is compiled, since there is some implicit conversion from nullptr
to optional
.
Upvotes: 7