为什么包含会<utility>破坏 GCC 中的结构化绑定?
Why does including <utility> break structured bindings in GCC?
考虑:
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{};
^~~~~~
这是怎么回事?编译器错误,或者这就是结构化绑定应该的工作方式?
这是编译器错误 78939。虽然它比这要复杂一些 - 核心语言和库之间有一些相互矛盾的问题(GB 20、LWG 2770 和 LWG 2446),这导致了 gcc/libstdc++ 在这里表现出的那种行为。当然,代码可以在有或没有#include <utility>
的情况下工作,这只是标准措辞正确到达那里的问题。
是的,具有所有公共非匿名工会成员的类应该可以在 [dcl.struct.bind]/4 的结构化绑定声明中使用:
否则,
E
的所有非静态数据成员都应是E
或同一明确的公共基类E
的公共直接成员,E
不得有匿名工会成员,并且标识符列表中的元素数量应等于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
机制。
结构化绑定背后的核心思想是std::tuple_size<T>
定义了你从解压缩T
中获得的组件数量,T::get<N>
应该访问第 N 个元素。毫不奇怪,这个std::tuple_size<T>
是<utility>
中基本模板的专业化。
现在在这种情况下,Point
没有对结构化绑定的此类支持,但这是一种特殊情况(所有公共非静态成员),C++17 声明不需要特殊的解包支持。这是上述规则的例外。
编译器在这里绊倒了自己,并在看到来自<utility>
的非专用std::tuple_size
时尝试使用通用规则。
- 在基于范围的for循环中使用结构化绑定声明
- 使用结构化绑定'Reflection'
- 为什么结构化绑定不使用"auto&"返回对结构成员的引用,而是返回成员本身
- 为什么 boost::comb 对结构化绑定的支持缺少结构化绑定机制对 boost::tuples::cons 的适应?
- 结构化绑定初始值设定项表单 { 赋值表达式 } 对于 clang 上的数组类型失败
- 在 C++14 中手动实现结构化绑定
- 为什么结构化绑定不支持可变数组?
- 在只读(即 const)访问器上执行结构化绑定的最佳实践是什么?
- 带有 std::minmax 和 rvalues 的结构化绑定
- 在无序映射的结构化绑定中推导类型
- 为什么基于范围的 for 循环中的结构化绑定只是一个副本而不是引用?
- 您自己的类型的结构化绑定,不是结构或元组(通过公共成员函数)
- 结构化绑定:遍历元组的双端面
- 结构化绑定是否适用于 std::vector?
- 结构化绑定,无需复制即可获取子向量的连续元素
- 成员变量的结构化绑定
- 结构化绑定语法是否可以在多态 lambda 中使用
- 结构化绑定的用例是什么?
- C++ 有关unordered_map的结构化绑定问题
- 结构化绑定是否可重用?