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

Недавно я понял, что в 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}?

2 ответа

Решение

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

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

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

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

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

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

Изменить: Подробнее о правилах конструктора (снова акцент мой):

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

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

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

Другие вопросы по тегам