Вызов конструктора с фигурными скобками вместо паратезов

Недавно я понял, что в C ++ 11 мы можем вызвать делегирующий конструктор списка инициализатора, например

Foo() : Foo{42} // delegate to Foo(initializer_list<>)

Этот синтаксис правильный? Вроде бы, хотя я бы ожидал всегда использовать круглые скобки при вызове функции, например Foo({42}), Пример кода ниже компилирует нормально в обоих Clang ++ и G ++

#include <iostream>
#include <initializer_list>

struct Foo
{
Foo() : Foo{42} // I would have expected invalid syntax, use Foo({42})
{
std::cout << "Foo()... delegating constructor\n";
}
Foo(std::initializer_list<int>)
{
std::cout << "Foo(initializer_list)\n";
}
};

int main()
{
Foo foo;
}

Я хорошо осведомлен о единообразной инициализации, как объявление объекты с помощью { }, но не знал, что мы можем также вызвать конструкторы. Мы не могу вызывать функции, хотя, следующее не компилируется:

#include <initializer_list>

void f(std::initializer_list<int>){}

int main()
{
f{5}; // compile time error, must use f({5})
}

Итак, подведем итог: мой вопрос заключается в следующем: существуют ли специальные правила при делегировании конструкторов, которые позволяют вызывать конструктор списка инициализации с использованием только фигурных скобок, например Foo{something}?

1

Решение

Да мем-инициализатор такие как Foo{42} может содержать в скобках список_выражений или приготовился-INIT-лист. Это имеет место независимо от того, является ли мем-инициализатор-идентификатор обозначает класс конструктора, базовый класс или член: то есть, когда конструктор делегирует, а когда нет. Смотрите грамматику в [class.base.init].

Кроме того, стандарт указывает ([class.base.init] / 7 в C ++ 14), что инициализация список_выражений или же приготовился-INIT-лист происходит по обычным правилам инициализации. Поэтому, если инициализатор является приготовился-INIT-лист затем std::initializer_list конструкторы будут иметь преимущество в разрешении перегрузки.

5

Другие решения

Я думаю, что правило довольно ясно, что вам будет разрешено делегировать конструктор списка инициализатора (выделение мое):

Если имя самого класса отображается как идентификатор класса или в
список инициализатора члена, тогда список должен состоять из этого одного члена
только инициализатор; такой конструктор известен как делегирование
конструктор, и конструктор, выбранный единственным членом
список инициализатора является целевым конструктором. цель
конструктор выбирается по разрешению перегрузки
и выполняется первым,
затем элемент управления возвращается к делегирующему конструктору, и его тело
казнены.

Таким образом, с помощью разрешения перегрузки вы можете вызывать конструктор списка инициализатора так же, как если бы вы вызывали его в «нормальном» коде, потому что.

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

Редактировать: Больше о правилах конструктора (Акцент опять мой):

Тело определения функции любого конструктора перед
открывающая скобка составного оператора, может включать в себя член
список инициализатора, синтаксис которого представляет собой символ двоеточия:
, с последующим
разделенный запятыми список одного или нескольких инициализаторов-членов, каждый из
который имеет следующий синтаксис
     идентификатор класса или идентификатора (список выражений (необязательно)) (1)
     класс-или-идентификатор brace-init-list (2) (начиная с C ++ 11)
      пакет параметров … (3) (начиная с C ++ 11)

1) Инициализирует базу или член, названный по классу или идентификатору, используя
прямая инициализация или, если выражение-список пуст,
Значение инициализация
2) Инициализирует базу или член, названный
класс-или-идентификатор с использованием инициализации списка (который становится
значение-инициализация, если список пуст, и агрегат-инициализация
при инициализации агрегата)

3) Инициализирует несколько баз, используя
расширение пакета

Таким образом, согласно № 2, это кажется законным.

2

По вопросам рекламы [email protected]