考虑:
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{};
^~~~~~
这里发生了什么?一个编译器错误,或者这是结构化绑定应该如何工作?
答案 0 :(得分:19)
这是编译器错误78939。虽然它比这复杂一点 - 核心语言和库之间存在一些相互矛盾的问题(GB 20,LWG 2770和LWG 2446),导致gcc / libstdc ++在这里展示的那种行为。当然意图代码在有或没有#include <utility>
的情况下工作,它只是标准措辞的正确问题。
是的,具有所有公共非匿名联盟成员的类应该可用于[dcl.struct.bind]/4的结构化绑定声明:
否则,
E
的所有非静态数据成员都应是E
的公共直接成员或E
E
的同一明确公共基类。{ 1}}不应具有匿名联合成员,并且标识符列表中的元素数量应等于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
机制。
答案 1 :(得分:12)
结构化绑定背后的核心思想是std::tuple_size<T>
定义从解包T
获得的组件数量,T::get<N>
应该访问第N个元素。不足为奇,此std::tuple_size<T>
是<utility>
中基本模板的专精。
现在在这种情况下,Point
没有对结构化绑定的支持,但它是一个特殊情况(所有公共非静态成员),C ++ 17声明没有特殊的解包支持需要。这是上述规则的一个例外。
编译器在这里绊倒自己,并在从std::tuple_size
看到未经专门化的<utility>
时尝试使用通用规则。