Why doesn't the `explicit` keyword prevent a `char` from being converted into an `int`?

Viewed 76

From what I understand, in the following code, explicit A(int a) should prevent A b('g'); to use the int constructor:

#include <iostream>

class A
{
    public:
        int x;
        char *y;

        A() : x(0) {}
        explicit A(int a) : x(a) { std::cout<<"INT\n"; }
        A(char *b) : y(b) { std::cout<<"C STRING\n"; }
};

int main()
{
    A a(5); /// output: "INT"
    A b('g'); /// output: "INT"
    A c("Hello"); /// output: "C STRING"
}

However, A b('g'); uses the int constructor... Why?

Also, another question: If I write A(const char *b) instead of A(char *b), it gives me the following error: invalid conversion from 'const char*' to 'char*' [-fpermissive]. Why can't I convert a const char* to char*?

2 Answers

You're using direct initialization, which does consider explicit constructors.

Direct-initialization is more permissive than copy-initialization: copy-initialization only considers non-explicit constructors and non-explicit user-defined conversion functions, while direct-initialization considers all constructors and all user-defined conversion functions.

Given A b('g');, 'g' is an char and could convert to int implicitly, then A::A(int) is called to initialize the object.

On the other hand, copy initialization like A a = 5; and A b = 'g'; won't work.

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

And about

Why can't I convert a const char* to char*?

const char* can't convert to char* implicitly. You can use const_cast, but note that it's dangerous, e.g. attempting to modify a string literal results in undefined behavior.

The explicit keyword prevents implicit conversion from int to A. However, it doesn't affect the possibility of char to int conversion when calling A constructor directly.

In other words, explicit only affects conversion to your class A but it doesn't affect any possible conversions of constructor parameters.

Related