Почему в том числе & lt; utility & gt; нарушать структурированные привязки в GCC?

Рассматривать:

struct Point { int x, y; };

int main()
{
const auto [x, y] = Point{};
}

Этот код прекрасно компилируется с gcc 7.1 в режиме C ++ 17, однако этот:

#include <utility>

struct Point { int x, y; };

int main()
{
const auto [x, y] = Point{};
}

выдает ошибку:

bug.cpp: In function 'int main()':
bug.cpp:7:16: error: 'std::tuple_size<const Point>::value' is not an integral constant expression
const auto [x, y] = Point{};
^~~~~~

Что тут происходит? Ошибка компилятора, или это то, как должны работать структурированные привязки?

20

Решение

Это ошибка компилятора 78939. Хотя это немного сложнее — между базовым языком и библиотекой было несколько противоречивых проблем (ГБ 20, LWG 2770, а также LWG 2446), что приводит к тому типу поведения, который gcc / libstdc ++ демонстрирует здесь. Это конечно предназначена что код работает с или без #include <utility>это просто вопрос стандартной формулировки, полученной там правильно.


Да, классы со всеми публичными неанонимными членами объединения должны использоваться в декларациях структурированных привязок согласно [Dcl.struct.bind] / 4:

В противном случае все EНестатические данные должны быть прямыми E или из того же однозначного общественного базового класса E, E не должен иметь анонимного члена объединения, а количество элементов в списке идентификаторов должно быть равно количеству элементов не статических данных E, Назначение нестатических данных членов E как m0, m1, m2, … (в порядке объявления), каждый vi является именем lvalue, которое относится к члену mi элемента e и типом которого является cv Ti, где Ti является объявленным типом этого члена; ссылочный тип cv Ti. Значение l является битовым полем, если этот элемент является битовым полем. [ Пример:

struct S { int x1 : 2; volatile double y1; };
S f();
const auto [ x, y ] = f();

Это совершенно не связано с включением <utility>ничто в этом коде не зависит от какой-либо функциональности библиотеки — члены захватываются напрямую, а не через get/tuple_size механизм.

18

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

Основная идея структурированных привязок заключается в том, что std::tuple_size<T> определяет, сколько компонентов вы получаете от распаковки T, а также T::get<N> должен получить доступ к N-му элементу. Не удивительно, это std::tuple_size<T> это специализация из базового шаблона в <utility>,

Теперь в этом случае Point не имеет такой поддержки структурированных привязок, но это особый случай (все открытые нестатические члены), для которого C ++ 17 заявляет, что никакой специальной поддержки распаковки не требуется. Это исключение из правила выше.

Компилятор отключается сам по себе и пытается использовать общее правило, когда видит несвойственное std::tuple_size от <utility>,

12

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