为什么包含 <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{};
^~~~~~
这是怎么回事?编译器错误,或者这就是结构化绑定的工作方式?
结构化绑定背后的核心思想是 std::tuple_size<T>
定义了您从解包中获得的组件数量 T
,并且 T::get<N>
应该访问第 N 个元素。毫不奇怪,这个 std::tuple_size<T>
是 <utility>
中基本模板的特化。
现在在这种情况下,Point
不支持结构化绑定,但这是 C++17 规定的一种特殊情况(所有 public 非静态成员)不需要特殊的拆包支持。这是上述规则的一个例外。
编译器在这里被自己绊倒了,当它看到来自 <utility>
的非专用 std::tuple_size
时,它试图使用通用规则。
这是编译器错误 78939. Although it's a bit more complicated than that - there were a few issues between the core language and the library that were mutually contradictory (GB 20, LWG 2770, and LWG 2446),它会导致 gcc/libstdc++ 在此处展示的那种行为。代码在有或没有 #include <utility>
的情况下都可以正常工作 ,这只是标准措辞是否正确的问题。
是的,类 和所有 public 非匿名联合成员应该可以在结构化绑定声明中使用 [dcl.struct.bind]/4:
Otherwise, all of E
's non-static data members shall be public direct members of E
or of the same unambiguous public base class of E
, E
shall not have an anonymous union member, and the number of elements in the identifier-list shall be equal to the number of non-static data members of E
. Designating the non-static data members of E
as m0, m1, m2, ... (in declaration order), each vi is the name of an lvalue that refers to the member mi of e and whose type is cv Ti, where Ti is the declared type of that member; the referenced type is cv Ti. The lvalue is a bit-field if that member is a bit-field. [ Example:
struct S { int x1 : 2; volatile double y1; };
S f();
const auto [ x, y ] = f();
这与包含 <utility>
完全无关,此代码中的任何内容都不依赖于任何库功能 - 成员是直接获取的,而不是通过 get
/tuple_size
机制。
考虑:
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{};
^~~~~~
这是怎么回事?编译器错误,或者这就是结构化绑定的工作方式?
结构化绑定背后的核心思想是 std::tuple_size<T>
定义了您从解包中获得的组件数量 T
,并且 T::get<N>
应该访问第 N 个元素。毫不奇怪,这个 std::tuple_size<T>
是 <utility>
中基本模板的特化。
现在在这种情况下,Point
不支持结构化绑定,但这是 C++17 规定的一种特殊情况(所有 public 非静态成员)不需要特殊的拆包支持。这是上述规则的一个例外。
编译器在这里被自己绊倒了,当它看到来自 <utility>
的非专用 std::tuple_size
时,它试图使用通用规则。
这是编译器错误 78939. Although it's a bit more complicated than that - there were a few issues between the core language and the library that were mutually contradictory (GB 20, LWG 2770, and LWG 2446),它会导致 gcc/libstdc++ 在此处展示的那种行为。代码在有或没有 #include <utility>
的情况下都可以正常工作 ,这只是标准措辞是否正确的问题。
是的,类 和所有 public 非匿名联合成员应该可以在结构化绑定声明中使用 [dcl.struct.bind]/4:
Otherwise, all of
E
's non-static data members shall be public direct members ofE
or of the same unambiguous public base class ofE
,E
shall not have an anonymous union member, and the number of elements in the identifier-list shall be equal to the number of non-static data members ofE
. Designating the non-static data members ofE
as m0, m1, m2, ... (in declaration order), each vi is the name of an lvalue that refers to the member mi of e and whose type is cv Ti, where Ti is the declared type of that member; the referenced type is cv Ti. The lvalue is a bit-field if that member is a bit-field. [ Example:struct S { int x1 : 2; volatile double y1; }; S f(); const auto [ x, y ] = f();
这与包含 <utility>
完全无关,此代码中的任何内容都不依赖于任何库功能 - 成员是直接获取的,而不是通过 get
/tuple_size
机制。