Конструктор мешает переменной, назначенной инициализатору?

Некоторое время назад можно было использовать «назначенный инициализатор» в 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

11

Решение

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

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

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

Особенность языка | Предложение | Доступно в GCC?

Назначенные инициализаторы | P0329R4 | 8

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

Если braced-init-list содержит назначенный-initializer-list, 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: неверное разрешение перегрузки при использовании назначенных инициализаторов мы видим в этом примере:

Другой контрольный пример, уменьшенный с Chromium 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 игнорирует имена полей во время разрешения перегрузки. Что объясняет странное поведение, которое вы видите, и то, что мы получаем правильную диагностику, когда удаляем конструктор.

5

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

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

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

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

7

По вопросам рекламы [email protected]