Разница между T t {x} и T t = {x} для целочисленного или перечисляемого типа?
В С++ 14:
Для любого интегрального или перечисляемого типа T
и для любого выражения expr
:
Есть ли разница между:
struct S { T t { expr }; };
и
struct S { T t = { expr }; };
Update:
Я добрался до [dcl.init.list]p3b5
, который гласит:
Если в списке инициализаторов есть один элемент типа E, и либо T не является ссылочным типом, либо его ссылочный тип связан с ссылкой на E, объект или ссылка инициализируются из этого элемента.
Я считаю, что эта цитата применима как к инициализации direct-list-initialization, так и к инициализации списка копий.
Итак, я думаю, что ответ отрицательный, нет никакой разницы.
Ответы
Ответ 1
Если вы посмотрите прямую инициализацию и инициализация копии, вы найдете те же слова:
если T является неклассовым типом, стандартные преобразования используются, если необходимо, для преобразования значения другого в cv-неквалифицированную версию T
поэтому не должно быть разницы. Разница этих инициализаций применяется только для типов классов: инициализация копирования не учитывает конструкторы explicit
и explicit
пользовательские операторы преобразования, прямая инициализация делает. Интегральные и перечисляемые типы не имеют ни одного из них.
Edit:
@ᐅ Johannes Schaub - litb ᐊ ответил на относительный вопрос к этому (только о скобках, а не в фигурных скобках), и он называет 8.5/14
аналогичной формулировкой (акцент мой)
Форма инициализации (с использованием круглых скобок или =) обычно незначительно, но имеет значение, когда инициализатор или объект инициализируется тип класса; Смотри ниже. Если сущность initialized не имеет типа класса, список выражений в Инициализатор в скобках должен быть одним выражением.
Я не мог найти аналог {}
в стандарте. Я надеюсь, что это достаточно аргументов для поддержки ответа нет разницы.
Ответ 2
-
struct S {T t { expr };};
- это инициализатор нестатических данных
что не использует знак равенства.
-
struct S{T t = { expr };};
- это инициализатор нестатических данных
что использует знак равенства.
Первый случай - инициализация прямого списка, а вторая - инициализация списка копий.
Разница между инициализацией direct-list-initialization и initial-list-initial заключается в том, что для первого случая рассматриваются как явные, так и неявные конструкторы, а для второго толькосильные > не явные конструкторы могут быть вызваны.
Чтобы прояснить, рассмотрим следующий пример:
struct Foo {
int i;
explicit Foo(int i_) : i(i_) {}
};
struct Bar {
Foo f {1};
};
Live Demo
В этом примере Foo
имеет конструктор explicit
и Bar
direct инициализирует свой член f
типа Foo
. Пример кода компилируется отлично, поскольку для прямой инициализации рассматриваются конструкторы explicit
и non-explicit
.
Теперь мы изменим этот пример, преобразуя инициализатор элементов нестатического данных без использования знака равенства, то есть случай инициализации прямого списка для инициализатора нестатических данных с использованием знака равенства, который равен случай инициализации списка копий.
struct Foo {
int i;
explicit Foo(int i_) : i(i_) {}
};
struct Bar {
Foo f = {1};
};
Live Demo
Теперь приведенный выше пример не компилирует и не испускает ошибку:
ошибка: выбранный конструктор явственен при копировании-инициализации
Ожидается, что, как уже упоминалось в инициализации списка копий, могут вызываться только неявные конструкторы.
Теперь для счетчиков и других интегральных типов разница, отображаемая выше, не будет применяться (т.е. не задействованы никакие конструкторы). Таким образом, два утверждения (т.е. [1] и [2]) будут эквивалентны.
Но ради полноты рассмотрим следующие примеры:
enum class Foo {A, B, C};
struct Bar {
Foo f{Foo::A};
};
и
enum class Foo {A, B, C};
struct Bar {
Foo f = {Foo::A};
};
Оба примера компилируются отлично.
Также рассмотрим следующие примеры:
struct Bar {
int i {1};
};
и
struct Bar {
int i = {1};
};
Оба примера также отлично компилируются.