Инициализация фигурной скобки через возвращаемое значение функции дает «лишние элементы»; ошибка

Учитывая следующий фрагмент кода:

class Foo {};
Foo makeFoo() { return Foo{}; }

int main()
{
Foo myFoo{makeFoo()};
}

Я ожидаю, что одна строка в main объявить и определить / инициализировать myFoo с помощью FooПереместить конструктор на возвращаемое значение makeFoo(),

Тем не менее, я получаю следующую ошибку от clang++ 3.5.1 (компиляция в режиме C ++ 14):

error: excess elements in struct initializer
Foo myFoo{makeFoo()};
^~~~~~~~~
1 error generated.

Что тут происходит? Что конкретно означает «struct initializer» — это просто конструктор по умолчанию (без аргументов) для POD? Почему не вызывается конструктор перемещения?

2

Решение

В конце концов, не существует такого понятия, как «универсальный (или равномерный) синтаксис инициализации». Инициализация списка имеет некоторые особенности поведения.

В вашем случае соответствующие правила находятся в разделе 8.5.1:

Агрегат — это массив или класс (раздел 9) без предоставленных пользователем конструкторов (12.1), без закрытых или защищенных нестатических элементов данных (пункт 11), без базовых классов (пункт 10) и без виртуальных функций (10.3 ).

Ваш class Foo поэтому является совокупный.

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

Вот как компилятор интерпретирует ваш код (как отмечает @chris, в следующей версии C ++ этого не произойдет … хотя я бы сказал, что это правило также необходимо обновить, просто «как указано в 8.5.4 «на самом деле недостаточно, чтобы остановить агрегатное поведение при инициализации).

Поскольку инициализаторов больше, чем членов, это незаконно.

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

Это правило разрешает инициализацию копирования / перемещения. Копирование / перемещение агрегата не может использовать фигурные скобки.

7

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

поскольку Foo, является агрегатом, выполняется агрегатная инициализация.

N3797 §8.5.4 [dcl.init.list] / 3:

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

  • Если T является агрегатом, выполняется агрегатная инициализация (8.5.1).

Кажется, это было изменено для C ++ 17, в соответствии с N4296:

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

  • Если T является типом класса и список инициализатора имеет
    один элемент типа cv U, где U — это T или класс, производный от T,
    объект инициализируется из этого элемента (путем копирования-инициализации
    для копирования списка инициализации или прямой инициализации для
    прямой список инициализации).
4

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector