Неопределенность вывода списка инициализаторов и структурированных привязок в C ++ 17

Я всегда избегал инициализаций, подобных следующему

const auto& x = a, y = b;
const int* const x = ptr_1, *const y = ptr_2;  // wot

По той причине, что ссылки и квалификаторы указателей не применяются к обеим инициализациям. Конечно, это одна из первых вещей, которую начинают изучать новички. Неоднозначность, связанная с этим, заставляет меня чувствовать, что следующее яснее и требует меньше внимания со стороны читателя

const auto& x = a;
const auto& y = b;

С C ++ 17 и структурированными привязками я был счастлив и увидел большой потенциал. C ++ 17 объявил вне закона то, что C ++ 14 и C ++ 11 не удалось исправить, auto x {1} является int и не std::initializer_list<int>, Но почему следующий код не работает?

const auto& [x, y] {a, b};
const auto& [x, y] = {a, b};

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

initializer for variable '[a, b]' with type 'const auto &' contains multiple expressions

Можно ли как-то объявить x и y с синтаксисом структурированных привязок, не прибегая к кортежам, парам и т. П.? Кроме того, почему первый в приведенном выше примере кода плохо сформирован? Есть ли двусмысленность в этом синтаксисе?

2

Решение

Структурное связывание, так сказать, для «распаковки» вещей. Он не предназначен для объединения обычных объявлений. Тот const auto& не относится ни к одному a ни bнесмотря на внешний вид.

Ваша конкретная попытка нарушает [Dcl.dcl] / 8:

простая декларация с идентификатор-лист называется
декларация структурированного связывания ([Dcl.struct.bind]). […] инициализатор должен иметь форму «= assignment-expression «Вида»{ assignment-expression }«, или же
формы «( assignment-expression )«, где
Назначение выражение имеет массив или не объединенный тип класса.


int a = 1, b = 2;
const auto bitand <:x, y:> = std::tie(a, b);

Это объявление структурированной привязки (очень) примерно эквивалентно

const auto bitand __e = std::tie(a, b); // hidden variable
auto and x = std::get<0>(__e);
auto and y = std::get<1>(__e);

(Реальная вещь использует tuple_elementне auto.)

Заметки:

  • const auto bitand относится к скрытая переменная и только скрытая переменная. x а также y всегда ссылки, даже если вы пишете только auto; является ли их референт const зависит от const свойства распространения типа инициализатора.
  • Временный материализованный из инициализатора prvalue срок службы будет продлен привязкой ссылки.
  • В этом примере оба x а также y имеют тип «ссылка на int»; это действительно написать x = 1;,
  • Существует специальная обработка для структурированных привязок в decltype формулировка.

Эта семантика неудивительна, если мы говорим о распаковке структуры и т. Д. С двумя членами «ссылка на int»; const на такие вещи на самом деле не влияет константность референта. OTOH, вас ждет неприятный сюрприз, если вы захотите использовать объявления структурированной привязки для того, для чего они не предназначены.

3

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

Этот синтаксис просто не поддерживается. Вы можете распаковать только агрегатные классы и объекты, для которых std::get был перегружен: https://skebanga.github.io/structured-bindings/

К сожалению, вы не можете использовать классное руководство по выводу, потому что вы хотите ссылку на a а не член кортежа. Таким образом, вы должны выписать список параметров шаблона.

#include <tuple>

int main()
{
int a = 1;
int b = 2;
const auto& [x, y] = std::tuple<int&,int&>{a, b};
}

Вы также не можете быть таким же глупым, как я, и правильно читать документы.

#include <tuple>

int main()
{
int a = 1;
int b = 2;
const auto& [x, y] = std::forward_as_tuple(a, b);
}

const auto& [x, y] = std::tie(a, b); работает так же.

0

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