Search code examples
c++overload-resolutionexplicit

Overload Resolution: What is the role of explicit and the initialization syntax?


Suppose I have an immutable String class as follows:

#include <iostream>
#include <string>

class String
{
public:
    explicit String(const char *Value) : Size(std::strlen(Value)), Value(new char[Size + 1])
    {
        std::memcpy(this->Value, Value, Size + 1);
        std::cout << Value << ", novice." << Size << std::endl;
    }
    template <typename T, std::size_t N> String(const T (&Value)[N]) : Size(N - 1), Value(new char[N])
    {
        std::memcpy(this->Value, Value, N);
        std::cout << Value << ", expert." << Size << std::endl;
    }
    ~String()
    {
        delete[] Value;
    }
private:
    const std::size_t Size;
    char *Value;
};

void main()
{
    auto &s = "Welcome to C++";
    String string = s;
    String str {s};
    String st(s);
    return;
}

I want to know the role explicit plays and how the initialization syntax makes a difference when the constructor overload is chosen.


I understand that for str and st, I am explicitly calling the constructor that takes a pointer to const char, so they print out:

Welcome to C++, novice.
Welcome to C++, novice.

But I don't understand why for string

Welcome to C++, expert.

is printed out. Please clarify how the overload is being selected.


Solution

  • With

    String str {s};
    String st(s);
    

    The

    explicit String(const char *Value)
    

    The reason the pointer overload is chosen is because it is not templated. Both the pointer and the array constructors are considered as an exact match to s so it would be an ambiguity but since the array constructor is a template it is consider less of a match then the pointer constructor. Even if you removed the explicit the pointer overload would still be chosen.

    Now with

    String string = s;
    

    explicit does matter because s is not a String. This means the compiler needs to implicitly convert it to one so it chooses the array constructor as it is an exact match and the only viable constructor as explicit constructors cannot be used in implicit conversions.