3

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*?

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
H-005
  • 467
  • 3
  • 15
  • 2
    Because that's what the standard requires. Given `A b('g')` the compiler looks for a constructor call that involves no more than a single implicit conversion of the `char` (i.e. `'g'`). It finds no constructor that accepts a `char` (by either value or `const` reference) but does find the constructor that accepts an `int`. A single implicit conversion can be used to convert from `char` to `int`, so the compiler converts `'g'` to `int`, and then calls the constructor that accepts an `int`. – Peter Aug 09 '20 at 11:31
  • Yes, but shouldn't the **explicit** keyword avoid that by not allowing **any** implicit conversions? – H-005 Aug 09 '20 at 12:02
  • @H-005 No, it only affects the user-defined conversion function which is marked as `explicit`, like `A::A(int)` in your code. It won't affect standard conversion like `char` to `int`. – songyuanyao Aug 09 '20 at 12:33
  • The `explicit` keyword means that `A x = 2` or `A y = 'g'` will fail, but `A x(2)` and `A y('g')` will not. It has nothing to do with implicit conversions (like converting `'g'` from `char` to `int`) affecting the choice of which constructor will be invoked. – Peter Aug 09 '20 at 14:56

2 Answers2

3

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
3

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.

r3mus n0x
  • 5,954
  • 1
  • 13
  • 34