Подтвердить что ты не робот

Синтаксис Nicer для установки значения аргумента по умолчанию для конструктора по умолчанию

Можно было бы объявить функцию с аргументом и указать, что значение по умолчанию для аргумента является результатом конструктора по умолчанию типа:

void foo(a::really::long::type::name arg = a::really::long::type::name());

Есть ли более сильный синтаксис для этого, который не предполагает ввода имени типа дважды? Что-то вроде:

void foo(a::really::long::type::name arg = default);

Я понимаю, что я могу typedef использовать имя типа, чтобы сделать его более красивым, но мне любопытно, существует ли такой синтаксис.

4b9b3361

Ответ 1

Да:

void foo(a::really::long::type::name arg = {});

Подводя итог следующим стандартным определениям:

Это инициализация списка. В зависимости от типа выполняется инициализация агрегата или объект инициализируется значением, которое, в свою очередь, подразумевает инициализацию по умолчанию или нуль.

Некоторые "угловые" случаи - это когда тип является специализацией std::initializer_list или когда тип имеет конструктор std::initializer_list (он вызывается, если он не имеет конструктора по умолчанию)


Соответствующие стандартные кавычки (чтобы мы встречались с определениями):

§8.3.6 Аргументы по умолчанию [dcl.fct.default]

1 Если в объявлении параметра указано предложение initializer, это Параметр initializer используется как аргумент по умолчанию

5 Аргумент по умолчанию имеет те же семантические ограничения, что и инициализатор в объявлении переменной типа параметра, используя семантику инициализации копирования (8.5)

§8.5.4 List-initialization [dcl.init.list]

1 Инициализация списка - это инициализация объекта или ссылки из скопированного списка инициализации. Такой инициализатор называется инициализатором список, [...]. Список инициализаторов может быть пустым. Инициализация списка может происходят в контекстах с прямой инициализацией или инициализацией копии; [..] инициализация списка в контекст копирования-инициализации называется copy-list-initialization.

3 Список-инициализация объекта или ссылки типа T определяется следующим образом:

  • Если T является агрегатом, выполняется инициализация (8.5.1)
  • В противном случае, если в списке инициализаторов нет элементов, а T - класс type с конструктором по умолчанию, объект инициализирован значением.
  • В противном случае, если T является специализацией std:: initializer_list, объект initializer_list prvalue сконструирован, как описано ниже, и используется для инициализации объекта в соответствии с правилами для инициализация объекта из класса того же типа (8.5).
  • В противном случае, если T - тип класса, рассматриваются конструкторы. Соответствующие конструкторы перечислены, и лучший выбирается с помощью разрешения перегрузки (13.3, 13.3.1.7) [...]
  • ...
  • В противном случае, если в списке инициализаторов нет элементов, объект инициализируется значением.

§ 8.5 Инициализаторы [dcl.init]

8 Для value-initialize объект типа T означает:

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

7 Для default-initialize объект типа T означает:

  • если T - тип класса (возможно, cv-qualit) (раздел 9), конструктор по умолчанию (12.1) для T называется (и инициализация плохо сформированный, если T не имеет конструктора по умолчанию или разрешения перегрузки (13.3) приводит к двусмысленности или в функции, которая удалена или недоступный из контекста инициализации);
  • если T - тип массива, каждый элемент по умолчанию инициализирован;
  • в противном случае инициализация не выполняется.

6 Для нулевой инициализации объект или ссылка типа T означает:

  • если T - скалярный тип (3.9), объект инициализируется значением, полученным преобразованием целочисленного литерала 0 (ноль) в T;
  • если T является (возможно, cv-квалифицированным) классом неединичного класса, каждый нестатический член данных и каждый подобъект базового класса нулевое инициализирование и заполнение инициализируются нулевыми битами;
  • если T является (возможно, cv-квалифицированным) типом объединения, объекты первого нестатического именованного элемента данных ноль инициализируются, а заполнение - инициализируется нулевыми битами;
  • если T - тип массива, каждый элемент инициализируется нулем;
  • если T является ссылочным типом, инициализация не выполняется.

§13.3.1.7 Инициализация с помощью инициализации списка [over.match.list]

1 Когда объекты неагрегатного типа типа T инициализируются списком (8.5.4), разрешение перегрузки выбирает конструктор в две фазы:

  • Изначально функции-кандидаты являются конструкторами-конструкторами инициализатора (8.5.4) класса T, а список аргументов состоит из список инициализаторов как один аргумент.
  • Если не найден жизнеспособный конструктор списка инициализаторов, снова выполняется разрешение перегрузки, где все функции-кандидаты конструкторы класса T и список аргументов состоят из элементы списка инициализаторов.

Если в списке инициализаторов нет элементов, а T имеет значение по умолчанию конструктор, первая фаза опущена. [...]

Ответ 2

Пешеходный подход возможен, если вы управляете классом arg. Используйте конструктор преобразования, перегруженный для enum:

// Define this enum, and then write constructors which take dfl
enum dfl { dflval };

class a_really_long_type_name {
public:
  a_really_long_type_name(dfl arg = dflval);
};

Теперь foo может быть:

void foo(a_really_long_type_name arg = dflval);

Если вы можете применить это, преимущество - переносимость; это должно хорошо работать в компиляторе на языке С++ за двадцать пять лет.

Множество классов могут делиться этим dfl enum и его dflval -прибранным нолем; это похоже на наличие нового ключевого слова.

Поскольку enum является отдельным типом, это не мешает перегрузкам конструктора для целых типов или символов и т.д.

Недостаток работает в некоторых классах, которые уже имеют конструкцию по умолчанию, предоставленную с помощью аргумента defaulting, что приводит к дублированию кода конструктора.