Назначение явных конструкторов по умолчанию - PullRequest
36 голосов
/ 14 мая 2010

Недавно я заметил класс в C ++ 0x, который вызывает явный конструктор по умолчанию. Однако мне не удается придумать сценарий, в котором конструктор по умолчанию можно вызывать неявно. Похоже, довольно бессмысленный спецификатор. Я подумал, что, возможно, это запретит Class c; в пользу Class c = Class();, но это не так.

Некоторые соответствующие цитаты из C ++ 0x FCD, поскольку мне легче ориентироваться [подобный текст существует в C ++ 03, если не в тех же местах]

12.3.1.3 [class.conv.ctor]

Конструктор по умолчанию может быть явным конструктором; такой конструктор будет использоваться для выполнения инициализации по умолчанию или инициализации значения (8.5).

Далее приводится пример явного конструктора по умолчанию, но он просто имитирует приведенный выше пример.

8,5,6 [decl.init]

По умолчанию инициализировать объект типа T означает:

- если T является (возможно, cv-квалифицированным) типом класса (раздел 9), вызывается конструктор по умолчанию для T (и инициализация некорректна, если у T нет доступного конструктора по умолчанию);

8.5.7 [decl.init]

Инициализация значения объекта типа T означает:

- если T является (возможно, cv-квалифицированным) типом класса (раздел 9) с предоставленным пользователем конструктором (12.1), то вызывается конструктор по умолчанию для T (и инициализация некорректна, если T не имеет доступный конструктор по умолчанию);

В обоих случаях стандартный вызов вызывает конструктор по умолчанию. Но это то, что произошло бы, если бы конструктор по умолчанию не был явным. Ради полноты:

8.5.11 [decl.init]

Если для объекта не указан инициализатор, объект инициализируется по умолчанию;

Из того, что я могу сказать, это просто оставляет преобразование без данных. Что не имеет смысла. Лучшее, что я могу придумать, будет следующим:

void function(Class c);
int main() {
  function(); //implicitly convert from no parameter to a single parameter
}

Но очевидно, что C ++ не обрабатывает аргументы по умолчанию. Что еще может заставить explicit Class(); вести себя иначе, чем Class();?

Конкретный пример, который породил этот вопрос, был std::function [20.8.14.2 func.wrap.func]. Для этого требуется несколько конвертирующих конструкторов, ни один из которых не помечен явным образом, но конструктор по умолчанию:

1 Ответ

28 голосов
/ 14 мая 2010

Это объявляет явный конструктор по умолчанию:

struct A {
  explicit A(int a1 = 0);
};

A a = 0; /* not allowed */
A b; /* allowed */
A c(0); /* allowed */

Если параметр отсутствует, как в следующем примере, explicit является избыточным.

struct A {
  /* explicit is redundant. */
  explicit A();
};

В некоторых черновиках C ++ 0x (я полагаю, это был n3035), это имело значение следующим образом:

A a = {}; /* error! */
A b{}; /* alright */

void function(A a);
void f() { function({}); /* error! */ }

Но в FCD они изменили это (хотя, я подозреваю, что они не имели в виду эту конкретную причину) в том, что все три случая value-initialize соответствующие объект. Инициализация значения не выполняет танец с перегрузочным разрешением и, следовательно, не сработает на явных конструкторах.

...