为什么结构化绑定只能与auto一起使用?

24

结构化绑定已经在c++17中引入。 它们允许从元组或结构体声明多个初始化变量。

这段代码可使用编译器进行编译。

#include <iostream>
#include <tuple>

int main() {
    auto tuple = std::make_tuple(1.0, 1);

    auto [ d, i ] = tuple;

    std::cout << "d=" << d << " i=" << i <<  '\n';

    return 0;
}

如果我没有使用auto来声明变量,我会得到以下错误:

错误:预期lambda表达式的主体 [d2, i2] = tuple;

#include <iostream>
#include <tuple>

int main() {
    auto tuple = std::make_tuple(1.0, 2);

    double d2;
    int i2;

    [d2 , i2] = tuple;

    return 0;
}

我使用的是clang version 4.0.0和编译选项-std=c++1z

我可以将现有变量分配给结构化绑定吗?我需要使用auto吗?


8
结构化绑定只能在定义和初始化变量时使用,不能作为一般的赋值语句(此情况下应使用 std::tie)。 - Some programmer dude
2个回答

19
你得到的错误信息非常明显,说明为什么它只允许使用auto:缺乏歧义会使语法更加上下文相关。
在表达式开头出现一对方括号表示一个lambda。你所要求的是标准规定有时[d2, i2]是捕获d2i2的lambda的开始,有时它是一个解包赋值。所有这些都取决于其后跟着什么。
将其添加到语言中并不值得复杂化。特别是,由于你已经有了std::tie可以针对元组做你想要的事情,正如某些程序员指出的那样
不仅如此,std::tie还允许你忽略一些解包的值,而结构化绑定目前不支持这一点。因此,这一切都归结为一种更有限的语法糖,用于执行标准库已经使用元组执行的操作。
哦,如果你不满意std::tie只能与元组一起使用,你可以扩展它以适用于任何POD。只需查看这个magic_get实现。人们可以将相同的思想应用于constexpr,将POD转换为引用元组,可以被馈送到std::tie中。就像这样:
std::tie(d2, i2) = magic_unpack(/*some POD that isn't a tuple*/);

3
我认为那并不完全正确。如果没有使用auto,你可以在结构化绑定之前添加一个关键字,就像这样:structured_binding [d2, i2] = tuple。其他人可以提出看起来不错的语法,但解析的工作量与auto一样。然后,您可以这样做:strucutured_binding [ bool d2, int i2]。这主要是我想要这个功能的原因,因为您可以使用显式类型的结构化绑定以及无默认构造函数的内容。 - iPherian
@iPherian - 那你错过了问题的重点。问题不在于为什么auto是关键字,而是为什么需要关键字。 - StoryTeller - Unslander Monica
@StoryTeller-UnslanderMonica 同意这一点 - iPherian提出了一个好点子 - 自动更改整数的符号或大小会很不错。auto [int n, double d, /* and the defaulting */ x] 在我看来完全可以,没有必要再加一个关键字... 或许也可以将值和引用结合起来:auto [&r, v] - Aconcagua
这不是不使用std::tuple [d1, i2] = tuple的原因。 - Tuff Contender
@TuffContender - 不,不这样做的原因是C++不是纯粹的标记汇编,而是真正区分关键字和库类型。你刚才提出的在语言工作方式上没有意义。 - StoryTeller - Unslander Monica
我在 http://wg21.link/p0480r1 中发现了这样一句话:“如果我使用结构化绑定,那么在一个强/具体的 API 界限中,绑定类型是最重要的,整个对象类型是无关紧要的”,不过我还有点怀疑。 - Tuff Contender

4
此外,你可以使用std::tie()将元组解包为其各个组成部分,例如:
#include <iostream>
#include <tuple>

int main() {
    auto tuple = std::make_tuple(1.0, 1);
    double d2;
    int i2;
    std::tie(d2, i2) = tuple;

    std::cout << "d2=" << d2 << " i2=" << i2 <<  '\n';

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接