21

考虑:

struct Point { int x, y; };

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

此代码在 C++17 模式下使用 gcc 7.1 编译得很好,但是这个:

#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{};
                ^~~~~~

这里发生了什么?编译器错误,或者这是结构化绑定应该如何工作?

4

2 回答 2

19

这是编译器错误78939。尽管它比这更复杂一些 - 核心语言和库之间存在一些相互矛盾的问题(GB 20LWG 2770LWG 2446),这导致了 gcc/libstdc++ 在这里展示的那种行为. 当然,无论是否使用,代码都可以正常工作#include <utility>,这只是标准措辞是否正确的问题。


是的,具有所有公共非匿名联合成员的类应该可以在每个[dcl.struct.bind]/4的结构化绑定声明中使用:

否则,所有E的非静态数据成员应是 的E或同一明确公共基类的公共直接成员EE不应有匿名联合成员,并且标识符列表中的元素数应等于的非静态数据成员数E。指定非静态数据成员E为 m0, m1, m2, ...(按声明顺序),每个 vi 是一个左值的名称,它引用 e 的成员 mi,其类型为 cv Ti,其中 Ti 是该成员的声明类型;引用的类型是 cv Ti。如果该成员是位域,则左值是位域。[ 例子:

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

这与包含 完全无关<utility>,此代码中的任何内容都不依赖于任何库功能 - 成员是直接获取的,而不是通过get/tuple_size机制。

于 2017-05-10T14:22:04.797 回答
12

结构化绑定背后的核心思想是std::tuple_size<T>定义您从 unpacking 获得多少组件T,并且T::get<N>应该访问第 N 个元素。毫不奇怪,这std::tuple_size<T><utility>.

现在在这种情况下,Point对结构化绑定没有这种支持,但它是一种特殊情况(所有公共非静态成员),C++17 声明不需要特殊的解包支持。这是上述规则的一个例外。

std::tuple_size编译器在这里绊倒自己,并在看到未专门化的 from时尝试使用通用规则<utility>

于 2017-05-10T14:15:11.243 回答