简体   繁体   中英

C++11 explicit conversion operators/constructors in return statement

I have a following example (with overly safe boolean type):

#include <cstdlib>

struct boolean_type
{

    explicit
    boolean_type(bool _value)
        : value_(_value)
    { ; }

    explicit
    operator bool () const
    {
        return value_;
    }

private :

    bool value_;

};

struct A
{

    A(int const _i) 
        : i_(_i)
    { ; }

    boolean_type operator == (A const & _other) const
    {
        return (i_ == _other.i_);
    }

private :

    int i_;

};

bool t()
{
    return A(0) == A(0);
}

int main()
{ 
    return EXIT_SUCCESS;
}

It is well-known that such code containing an errors: "could not convert '(((int)((const A*)this)->A::i_) == ((int) other.A::i ))' from 'bool' to 'boolean_type'" in return statement of bool A::operator == (A const &) const and "cannot convert 'boolean_type' to 'bool'" in return statement of bool t() . But what the risk here? Why there are not explicit conversion here in both cases? Why are implicit? In fact we explicitly specify the returning type bool in second case and static_assert(std::is_same< bool, decltype(std::declval< int >() == std::declval< int >()) >::value, "!"); as such!

Additionally want to say:

Due to the specified obstruction I cannot simply replace all entries of the bool to my super-safe boolean_type (which is mocked-object ) in my user code, because, say, in return statement of boost::variant::operator == uses above construction, that treats there as implicit conversion . Similar obstructions are not unique.

You have two implicit conversions. One here:

return (i_ == _other.i_);

And another here:

return A(0) == A(0);

These are implicit because you are not explicitly telling the compiler that you want to convert the result of the comparisons to boolean_type and bool respectively. These implicit conversions are not allowed because you made both the constructor and conversion operator of boolean_type explicit - that's the whole point of the explicit keyword.

You would need to do:

return static_cast<boolean_type>(i_ == _other.i_);

And:

return static_cast<bool>(A(0) == A(0));

The typical reason for making conversions to bool explicit is because the conversion may be used in situations that you did not intend it to be used. For example, if you had boolean_type objects called b1 and b2 with non- explicit conversions, you would be able to do the following:

b1 > 0
b1 == b2

These are probably not the intended uses of the boolean conversion operator.

Why there are not explicit conversion here in both cases?

Because the onus is on you , the programmer, to be explicit if you want an explicit conversion.

Implicit conversions would work in this case if you had allowed them. But you didn't allow them when you marked operator bool and boolean_type::boolean_type as explicit .

Why are implicit?

Because you did not write the conversion. You must:

  boolean_type operator == (A const & _other) const
  {   
      return boolean_type (i_ == _other.i_);
  }

...and:

bool t()
{   
    return (bool) (A(0) == A(0));
}

But what the risk here?

You tell us. explicit exists specifically to tell the compiler that there might be a risk in permitting some implicit conversions to take place. So when you marked those functions as explicit you said to the compiler:

Ok, if you allow an implicit conversion from a bool to a boolean_operator or vice versa, something bad might happen. So don't allow those implicit conversions.

You didn't tell the compiler (or us) why those implicit conversions are dangerous. You only said that they were .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM