Разница между String s1='a'; // ошибка: нет явного преобразования char в String String s2(10); // правильно: строка для хранения 10 символов
может показаться очень тонкой...
Но она несомненно есть. И дело тут вот в чем.
Запись X a=b;
всегда означает создание объекта a класса X посредством копирования значения некоторого другого объекта класса X. Здесь может быть два варианта:
Объект b уже является объектом класса X. В этом случае мы получим непосредственный вызов конструктора копирования: X a(b);
Объект b объектом класса X не является. В этом случае должен быть создан временный объект класса X, чье значение будет затем скопировано: X a(X(b));
Именно этот временный объект и не может быть создан в случае explicit-конструктора, что приводит к ошибке компиляции.
Еще одна тонкость состоит в том, что в определенных условиях реализациям разрешено не создавать временные объекты:
12.8 Копирование объектов классов [class.copy]
Там, где временный объект копируется посредством конструктора копирования, и данный объект и его копия имеют один и тот же тип (игнорируя cv-квалификаторы), реализации разрешено считать, что и оригинал и копия ссылаются на один и тот же объект и вообще не осуществлять копирование, даже если конструктор копирования или деструктор имеют побочные эффекты. Если функция возвращает объекты классов и return выражение является именем локального объекта, тип которого (игнорируя cv-квалификаторы) совпадает с типом возврата, реализации разрешено не создавать временный объект для хранения возвращаемого значения, даже если конструктор копирования или деструктор имеют побочные эффекты. В этих случаях объект будет уничтожен позднее, чем были бы уничтожены оригинальный объект и его копия, если бы данная оптимизация не использовалась.
Давайте не поленимся и напишем маленький класс, позволяющий отследить возникающие при этом спецэффекты. #include <stdio.h> #include <string.h>
struct A { static const int nsize=10;
char n[nsize];
A(char cn) { n[0]=cn; n[1]=0;