简体   繁体   English

C++17 中的初始化列表和结构化绑定推导歧义

[英]Initializer list and structured bindings deduction ambiguity in C++17

I had always avoided initializations like the following我一直避免像下面这样的初始化

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

For the reason that the reference and pointer qualifiers don't apply to both the initializations.由于引用和指针限定符不适用于这两个初始化。 Granted it's one of the first things beginners learn, the ambiguity associated with it makes me feel like the following is clearer and requires less thought on the reader's end诚然这是初学者学习的第一件事,与之相关的歧义让我觉得以下内容更清晰,读者需要更少的思考

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

With C++17 and structured bindings I was happy and saw lots of potential.使用 C++17 和结构化绑定,我很高兴并看到了很多潜力。 C++17 outlawed what C++14 and C++11 had failed to fix, auto x {1} is an int and not std::initializer_list<int> . C++17 取缔了 C++14 和 C++11 未能修复的内容, auto x {1}是一个int而不是std::initializer_list<int> But why does the following code not work?但是为什么下面的代码不起作用?

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

The latter is in line with the new rules for auto deduction and initializer lists, the expression on the right hand side is treated as an initializer list.后者符合自动推导和初始化列表的新规则,右侧的表达式被视为初始化列表。 But for the former compilation fails with the following error但是对于以前的编译失败并出现以下错误

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

Is there any way I can declare both x and y with the structured bindings syntax without having to resort to tuples, pairs and the like?有什么方法可以使用结构化绑定语法声明 x 和 y 而不必求助于元组、对等? Also why is the former in the code example above ill formed code?另外为什么上面的代码示例中的前者是格式错误的代码? Is there an ambiguity in that syntax?那个语法有歧义吗?

Structured binding is, so to speak, for "unpacking" things.可以说,结构化绑定用于“解包”事物。 It's not designed to be a way to combine normal declarations.它不是为了结合普通声明而设计的。 That const auto& applies to neither a nor b , despite the appearance.尽管外观如此, const auto&既不适用于a也不适用于b

Your particular attempt violates [dcl.dcl]/8 :您的特定尝试违反了[dcl.dcl]/8

A simple-declaration with an identifier-list is called a structured binding declaration ([dcl.struct.bind]).带有标识符列表的简单声明称为结构化绑定声明([dcl.struct.bind])。 [...] The initializer shall be of the form “ = assignment-expression ”, of the form “ { assignment-expression } ”, or of the form “ ( assignment-expression ) ”, where the assignment-expression is of array or non-union class type. [...]初始值设定项的形式应为“ = assignment-expression ”,形式为“ { assignment-expression } ”,或形式为“ ( assignment-expression ) ”,其中赋值表达式是数组或非联合类类型。


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

This structured binding declaration is (very) roughly equivalent to这个结构化绑定声明(非常)大致相当于

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

(The real thing uses tuple_element , not auto .) (真实的东西使用tuple_element ,而不是auto 。)

Notes:注意事项:

  • The const auto bitand applies to the hidden variable and only the hidden variable. const auto bitand适用于隐藏变量且仅适用于隐藏变量。 x and y are always references even if you write just auto ;即使你只写autoxy也总是引用; whether their referent is const depends on the const propagation properties of the initializer's type.它们的引用对象是否为const取决于初始化器类型的const传播属性。
  • A temporary materialized from a prvalue initializer will have its lifetime extended by the reference binding.从纯右值初始化器物化的临时对象将通过引用绑定延长其生命周期。
  • In this example, both x and y are of type "reference to int";在这个例子中, xy都是“对 int 的引用”类型; it is valid to write x = 1;x = 1;是有效的x = 1; . .
  • There's special treatment for structured bindings in the decltype wording.decltype措辞中有对结构化绑定的特殊处理。

These semantics are unsurprising if we are talking about unpacking a struct, etc., with two "reference to int" members;如果我们正在谈论使用两个“对 int 的引用”成员解压缩结构等,这些语义就不足为奇了; a const on such things doesn't actually affect the referent's constness.此类事物上的const实际上并不影响所指对象的const OTOH, you are in for a bad surprise if you want to use structured binding declarations for something they aren't designed to do. OTOH,如果您想将结构化绑定声明用于它们并非旨在做的事情,那么您会感到意外。

This syntax is just not supported.只是不支持此语法。 You can only unpack aggregate classes and objects which for which std::get has been overloaded: https://skebanga.github.io/structured-bindings/您只能解包std::get已重载的聚合类和对象: https : //skebanga.github.io/structured-bindings/

Unfortunately, you cannot really make use of the cool deduction guide because you want a reference to a and not to the tuple member.不幸的是,您不能真正使用很酷的推导指南,因为您想要引用a而不是元组成员。 Thus you have to write out the template parameter list.因此您必须写出模板参数列表。

#include <tuple>

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

You could also not be as stupid as me and read the docs correctly.您也不能像我一样愚蠢并正确阅读文档。

#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); works as well.也有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM