Недавно я понял, что в 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}
?
Да мем-инициализатор такие как Foo{42}
может содержать в скобках список_выражений или приготовился-INIT-лист. Это имеет место независимо от того, является ли мем-инициализатор-идентификатор обозначает класс конструктора, базовый класс или член: то есть, когда конструктор делегирует, а когда нет. Смотрите грамматику в [class.base.init].
Кроме того, стандарт указывает ([class.base.init] / 7 в C ++ 14), что инициализация список_выражений или же приготовился-INIT-лист происходит по обычным правилам инициализации. Поэтому, если инициализатор является приготовился-INIT-лист затем std::initializer_list
конструкторы будут иметь преимущество в разрешении перегрузки.
Я думаю, что правило довольно ясно, что вам будет разрешено делегировать конструктор списка инициализатора (выделение мое):
Если имя самого класса отображается как идентификатор класса или в
список инициализатора члена, тогда список должен состоять из этого одного члена
только инициализатор; такой конструктор известен как делегирование
конструктор, и конструктор, выбранный единственным членом
список инициализатора является целевым конструктором. цель
конструктор выбирается по разрешению перегрузки и выполняется первым,
затем элемент управления возвращается к делегирующему конструктору, и его тело
казнены.
Таким образом, с помощью разрешения перегрузки вы можете вызывать конструктор списка инициализатора так же, как если бы вы вызывали его в «нормальном» коде, потому что.
Однако я не знаю ничего, что позволяло бы вызывать функцию, которая принимает список инициализаторов так же, как вы можете вызывать конструктор с ним.
Редактировать: Больше о правилах конструктора (Акцент опять мой):
Тело определения функции любого конструктора перед
открывающая скобка составного оператора, может включать в себя член
список инициализатора, синтаксис которого представляет собой символ двоеточия:, с последующим
разделенный запятыми список одного или нескольких инициализаторов-членов, каждый из
который имеет следующий синтаксис
идентификатор класса или идентификатора (список выражений (необязательно)) (1)
класс-или-идентификатор brace-init-list (2) (начиная с C ++ 11)
пакет параметров … (3) (начиная с C ++ 11)1) Инициализирует базу или член, названный по классу или идентификатору, используя
прямая инициализация или, если выражение-список пуст,
Значение инициализация
2) Инициализирует базу или член, названный
класс-или-идентификатор с использованием инициализации списка (который становится
значение-инициализация, если список пуст, и агрегат-инициализация
при инициализации агрегата)
3) Инициализирует несколько баз, используя
расширение пакета
Таким образом, согласно № 2, это кажется законным.