Конструктор мешает переменной-члену назначить инициализатор? - PullRequest
0 голосов
/ 11 сентября 2018

Некоторое время назад можно было использовать «назначенный инициализатор» в GCC:

struct CC{
    double a_;
    double b_;
};

CC cc{.a_ = 1., .b_ = 2.}; assert(cc.a_ == 1. and cc.b_ == 2.); // ok
CC cc{.bla = 0., .bli = 0.}; // compile error

Однако, когда я добавляю конструктор, метки игнорируются.

struct CC{
    double a_;
    double b_;
    CC(double a, double b) : a_{a}, b_{b}{}
};

CC cc{.a_ = 1., .b_ = 2.}; assert(cc.a_ == 1. and cc.b_ == 2.); // ok
CC cc{.b_ = 2., .a_ = 1.}; // compiles but labels don't matter only the order, confusing
CC cc{.bla = 2., .bli = 1.}; // compiles but labels don't matter, confusing

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

Я обнаружил это случайно, с gcc 8.1 -std=c++2a.

Это ожидаемое поведение?

Ссылка: https://en.cppreference.com/w/cpp/language/aggregate_initialization

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Это ошибка gcc, она по-прежнему создает даже с параметром -pedantic , в котором мы должны получать предупреждения для любых расширений

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

и gcc утверждают, что поддерживают предложение P0329R4: Designated initializers для режима C++2a в соответствии с поддержкой стандартов C ++ на странице GCC :

Функция языка | Предложение | Доступно в GCC?
...
Назначенные инициализаторы | P0329R4 | 8

Для использования Назначенные инициализаторы тип должен быть агрегированным [dcl.init.list] p3.1 :

Если фигурный список инициализации содержит список назначенных инициализаторов, T должен быть агрегированным классом . Заказанный идентификаторы в обозначениях обозначенного-инициализатора-списка образуют подпоследовательность упорядоченного идентификаторы в непосредственных нестатических членах данных T. Агрегированная инициализация выполняется (11.6.1). [Пример:

struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // error: designator order does not match declaration order
A b{.x = 1, .z = 2}; // OK, b.y initialized to 0

- конец примера]

CC не является совокупностью согласно [dcl.init.aggr] :

Агрегат - это массив или класс (раздел 12) с
- (1.1) - нет пользовательских, явных или унаследованных конструкторов (15.1),
....

gcc отчет об ошибке

Если мы посмотрим на сообщение об ошибке gcc: неправильное разрешение перегрузки при использовании назначенных инициализаторов мы видим в данном примере:

Еще один контрольный пример, уменьшенный с хрома 70.0.3538.9 и принятый лязг:

  struct S { void *a; int b; };
  void f(S);
  void g() { f({.b = 1}); }

Это не с

  bug.cc: In function ‘void g()’:
  bug.cc:3:24: error: could not convert ‘{1}’ from ‘<brace-enclosed initializer list>’ to ‘S’
   void g() { f({.b = 1}); }
                        ^

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

Кажется, gcc игнорирует имена полей во время разрешения перегрузки. Что объясняет странное поведение, которое вы видите, и то, что мы получаем правильную диагностику при удалении конструктора.

0 голосов
/ 11 сентября 2018

Метки для обозначенных инициализаторов не должны игнорироваться компиляторами.Все три примера с конструктором должны быть некорректными.

Вы, вероятно, получаете это поведение из-за конфликта между назначенной функцией инициализатора C ++ 20 и назначенными инициализаторами в стиле C GCC, которые вы неявно используете.доступ из-за GCC просто дает их вам.Если бы GCC был должным образом совместим с C ++ 20, после того, как вы дали типу конструктор, он перестал бы быть агрегатом, и, следовательно, использование инициализатора было бы некорректным.

По сути, это ошибка драйверавызвано не-C ++ - стандартным поведением компилятора по умолчанию.Скорее всего, если вы отключите эту функцию, вы получите правильную ошибку компиляции для этих случаев.

...