Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit keyword applied to operator instead of constructor

In the class below,

Why would you make the operators explicit. I thought that explicit was to prevent implicit calling of constructors?

 class Content
            {
public:

 virtual ~Content() = 0;
 virtual explicit operator float&();
 virtual explicit operator long long&();
 virtual explicit operator std::string&()
}
like image 416
cherry aldi Avatar asked Sep 24 '18 15:09

cherry aldi


2 Answers

I thought that explicit was to prevent implicit calling of constructors?

Since C++11 it also applies to user-defined conversions (a.k.a. the cast operator).

Why would you make the operators explicit

Used in this context, the explicit keyword makes the conversion eligible only for direct-initialization and explicit conversions. See here under [class.conv.fct¶2]:

A conversion function may be explicit ([dcl.fct.spec]), in which case it is only considered as a user-defined conversion for direct-initialization ([dcl.init]). Otherwise, user-defined conversions are not restricted to use in assignments and initializations.

This aids you in making sure the compiler doesn't try the conversion against your intention, so that you have to explicitly cast it yourself, leaving less room for error. Example:

struct Foo
{
    explicit operator int() {return 0;}
    operator int*() {return nullptr;}
};

int main()
{
    Foo foo;

    //int xi = foo; // Error, conversion must be explicit
    int i = static_cast<int>(foo); // OK, conversion is explicit
    int* i_ptr = foo; // OK, implicit conversion to `int*` is allowed

    int i_direct(foo); // OK, direct initialization allowed
    int* i_ptr_direct(foo); // OK, direct initialization after implicit conversion

    return 0;
}

It can also help resolve ambiguity in cases where multiple conversion options apply, leaving the compiler without a criteria for deciding which one to choose:

struct Bar
{
    operator int() {return 1;}
    operator char() {return '1';}
};

int main()
{
    Bar bar;    
    //double d = bar; // Error, implicit conversion is ambiguous    
    return 0;
}

Add explicit:

struct Bar
{
    operator int() {return 1;}
    explicit operator char() {return '1';}
};

int main()
{
    Bar bar;    
    double d = bar; // OK, implicit conversion to `int` is the only option    
    return 0;
}
like image 78
Geezer Avatar answered Oct 17 '22 12:10

Geezer


Consider the following:

struct Content
{
    operator float() { return 42.f; }  
    friend Content operator+(Content& lhs, float) { return lhs; }
};

int main()
{
    Content c{};
    c + 0; //  error: ambiguous overload for 'operator+'
}

Here, the compiler cannot choose between operator+(Content&, float) and operator+(float, int). Making the float operator explicit resolves this ambiguity*:

c + 0; // operator+(Content&, float)

or

static_cast<float>(c) + 0; // operator+(float, int)

*) provided it makes sense to prefer one over the other.

like image 2
YSC Avatar answered Oct 17 '22 13:10

YSC