Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nullptr in ternary operator

Tags:

c++

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).

like image 726
Roel Avatar asked Sep 03 '15 14:09

Roel


1 Answers

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.

like image 197
ForEveR Avatar answered Oct 28 '22 04:10

ForEveR