Разница между 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};  
};

Оба примера также отлично компилируются.