2016-11-14 11 views
0

Предположим, у меня есть непреложный String класс следующим образом:Разрешение перегрузки: какова роль явного и синтаксиса инициализации?

#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; 
} 

Я хочу знать роль explicit пьесы и как синтаксис инициализации делает разницу, когда выбирается перегрузка конструктора.


Я понимаю, что для str и st, я явно вызвать конструктор, который принимает указатель на const char, поэтому они выдают:

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

Но я не понимаю, почему для string

Welcome to C++, expert. 

распечатан. Просьба уточнить, как выбирается перегрузка.

+0

Ваш класс строк является неизменным, если вы инициализируете его с помощью другой неизменной строки стиля C. Если у вас есть непостоянный массив символов и создайте объект String из этого массива, вы можете изменить его, и неизменяемый объект String также изменится. –

+0

Я понял это прямо сейчас. Благодаря! –

+2

@BoPersson Я не думаю, что обман правилен. Он играет роль, но здесь есть и другие вещи. – NathanOliver

ответ

1

С

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

explicit String(const char *Value) 

Причина выбирается перегрузка указатель, потому что это не шаблонный. Как указатель, так и конструкторы массива рассматриваются как точное соответствие s, поэтому было бы двусмысленно, но поскольку конструктор массива является шаблоном, он считается менее подходящим, чем конструктор указателя. Даже если вы удалили explicit, перегрузка указателя по-прежнему будет выбрана.

Теперь с

String string = s; 

explicit имеет значение, потому что s не String. Это означает, что компилятор должен неявно преобразовывать его в один, поэтому он выбирает конструктор массива, поскольку он является точным совпадением, и единственный жизнеспособный конструктор, поскольку явные конструкторы не могут использоваться в неявных преобразованиях.

+0

Таким образом, без «явного» перегрузки указателя вызывается, поскольку он не является шаблоном? –

+1

@AnirbanSarkar Да, потому что шаблон имеет более низкий приоритет, чем конструктор указателя. – NathanOliver

+0

Благодарим вас за разъяснение. –