Roel
Roel

Reputation: 19642

Nullptr in ternary operator

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

Answers (1)

ForEveR
ForEveR

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

Related Questions