Я всегда избегал инициализаций, подобных следующему
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 с синтаксисом структурированных привязок, не прибегая к кортежам, парам и т. П.? Кроме того, почему первый в приведенном выше примере кода плохо сформирован? Есть ли двусмысленность в этом синтаксисе?
Структурное связывание, так сказать, для «распаковки» вещей. Он не предназначен для объединения обычных объявлений. Тот 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
свойства распространения типа инициализатора.x
а также y
имеют тип «ссылка на int»; это действительно написать x = 1;
,decltype
формулировка.Эта семантика неудивительна, если мы говорим о распаковке структуры и т. Д. С двумя членами «ссылка на int»; const
на такие вещи на самом деле не влияет константность референта. OTOH, вас ждет неприятный сюрприз, если вы захотите использовать объявления структурированной привязки для того, для чего они не предназначены.
Этот синтаксис просто не поддерживается. Вы можете распаковать только агрегатные классы и объекты, для которых 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);
работает так же.