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.
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.