0

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.

Anirban Sarkar
  • 796
  • 6
  • 14
  • Your string class is only immutable if you initialize it with another immutable C-style string. If you have a non-constant array of characters and create a `String` object from that array, then you can still modify the array and the supposedly immutable `String` object will also change. – Some programmer dude Nov 14 '16 at 14:35
  • I realized that right now. Thanks! – Anirban Sarkar Nov 14 '16 at 14:37
  • 2
    @BoPersson I do not think that dupe is right. It plays a part but there is other things going on here as well. – NathanOliver Nov 14 '16 at 14:38
  • @Nathan - I think the answers to the other question is a very good match, [like this one](http://stackoverflow.com/a/121216/597607) using `explicit String`and everything. But you guys can reopen if you don't agree. – Bo Persson Nov 14 '16 at 14:40
  • Fixed, String is now immutable and slow. ;) – Anirban Sarkar Nov 14 '16 at 15:00
  • I did use `new` in the constructor initializer-list, and copied the string. Is it bad to do `new` in initializer list? – Anirban Sarkar Nov 14 '16 at 15:02
  • @AnirbanSarkar Oops. I missed that. I'll delete the comment. – NathanOliver Nov 14 '16 at 15:06

1 Answers1

1

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.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402