| // RUN: %clang_cc1 -fsyntax-only -std=c++26 %s -verify |
| |
| template <typename T> |
| struct type_ { }; |
| |
| template <typename ...T> |
| auto sum(T... t) { return (t + ...); } |
| |
| struct my_struct { |
| int a; |
| int b; |
| int c; |
| int d; |
| }; |
| |
| struct fake_tuple { |
| int arr[4] = {1, 2, 3, 6}; |
| |
| template <unsigned i> |
| int get() { |
| return arr[i]; |
| } |
| }; |
| |
| namespace std { |
| template <typename T> |
| struct tuple_size; |
| template <unsigned i, typename T> |
| struct tuple_element; |
| |
| template <> |
| struct tuple_size<fake_tuple> { |
| static constexpr unsigned value = 4; |
| }; |
| |
| template <unsigned i> |
| struct tuple_element<i, fake_tuple> { |
| using type = int; |
| }; |
| } |
| |
| |
| template <typename T> |
| void decompose_tuple() { |
| auto tup = T{{1, 2, 3, 6}}; |
| auto&& [x, ...rest, y] = tup; |
| |
| ((void)type_<int>(type_<decltype(rest)>{}), ...); |
| |
| T arrtup[2] = {T{{1, 2, 3, 6}}, |
| T{{7, 9, 10, 11}}}; |
| int sum = 0; |
| for (auto [...xs] : arrtup) { |
| sum += (xs + ...); |
| } |
| } |
| |
| template <typename T> |
| void decompose_struct() { |
| T obj{1, 2, 3, 6}; |
| auto [x, ...rest, y] = obj; |
| static_assert(sizeof...(rest) == 2); |
| |
| auto [...empty] = type_<int>{}; |
| static_assert(sizeof...(empty) == 0); |
| } |
| |
| template <typename T> |
| void decompose_array() { |
| int arr[4] = {1, 2, 3, 6}; |
| auto [x, ...rest, y] = arr; |
| |
| static_assert(sizeof...(rest) == 2); |
| int size = sizeof...(rest); |
| T arr2[sizeof...(rest)] = {rest...}; |
| auto [...pack] = arr2; |
| |
| // Array of size 1. |
| int arr1[1] = {1}; |
| auto [a, ...b] = arr1; |
| static_assert(sizeof...(b) == 0); |
| auto [...c] = arr1; |
| static_assert(sizeof...(c) == 1); |
| auto [a1, ...b1, c1] = arr1; // expected-error{{decomposes into 1 element, but 3 names were provided}} |
| } |
| |
| // Test case by Younan Zhang. |
| template <unsigned... P> |
| struct S { |
| template <unsigned... Q> |
| struct N { |
| void foo() { |
| int arr[] = {P..., Q...}; |
| auto [x, y, ...rest] = arr; |
| [&]() { |
| static_assert(sizeof...(rest) + 2 == sizeof...(P) + sizeof...(Q)); |
| }(); |
| } |
| }; |
| }; |
| |
| struct bit_fields { |
| int a : 4 {1}; |
| int b : 4 {2}; |
| int c : 4 {3}; |
| int d : 4 {4}; |
| }; |
| |
| template <typename T> |
| void decompose_bit_field() { |
| auto [...x] = T{}; |
| static_assert(sizeof...(x) == 4); |
| int a = x...[0]; |
| int b = x...[1]; |
| int c = x...[2]; |
| int d = x...[3]; |
| } |
| |
| template <typename T> |
| void lambda_capture() { |
| auto [...x] = T{}; |
| [=] { (void)sum(x...); }(); |
| [&] { (void)sum(x...); }(); |
| [x...] { (void)sum(x...); }(); |
| [&x...] { (void)sum(x...); }(); |
| } |
| |
| struct S2 { |
| int a, b, c; |
| }; |
| |
| auto X = [] <typename = void> () { |
| auto [...pack] = S2{}; |
| }; |
| |
| int main() { |
| decompose_array<int>(); |
| decompose_tuple<fake_tuple>(); |
| decompose_struct<my_struct>(); |
| S<1, 2, 3, 4>::N<5, 6>().foo(); |
| decompose_bit_field<bit_fields>(); |
| lambda_capture<int[5]>(); |
| lambda_capture<fake_tuple>(); |
| lambda_capture<my_struct>(); |
| X(); |
| |
| } |
| |
| // P1061R10 Stuff |
| namespace { |
| struct C { int x, y, z; }; |
| |
| template <class T> |
| void now_i_know_my() { |
| auto [a, b, c] = C(); // OK, SB0 is a, SB1 is b, and SB2 is c |
| auto [d, ...e] = C(); // OK, SB0 is d, the pack e (v1) contains two structured bindings: SB1 and SB2 |
| static_assert(sizeof...(e) == 2); |
| auto [...f, g] = C(); // OK, the pack f (v0) contains two structured bindings: SB0 and SB1, and SB2 is g |
| static_assert(sizeof...(e) == 2); |
| auto [h, i, j, ...k] = C(); // OK, the pack k is empty |
| static_assert(sizeof...(e) == 0); |
| auto [l, m, n, o, ...p] = C(); // expected-error{{{decomposes into 3 elements, but 5 names were provided}}} |
| } |
| } // namespace |
| |
| namespace { |
| auto g() -> int(&)[4]; |
| |
| template <unsigned long N> |
| void h(int (&arr)[N]) { |
| auto [a, ...b, c] = arr; // a names the first element of the array, |
| // b is a pack referring to the second and |
| // third elements, and c names the fourth element |
| static_assert(sizeof...(b) == 2); |
| auto& [...e] = arr; // e is a pack referring to the four elements of the array |
| static_assert(sizeof...(e) == 4); |
| } |
| |
| void call_h() { |
| h(g()); |
| } |
| } // namespace |
| |
| namespace { |
| struct D { }; |
| |
| int g(...) { return 1; } |
| |
| template <typename T> |
| constexpr int f() { |
| D arr[1]; |
| auto [...e] = arr; |
| return g(e...); |
| } |
| |
| constexpr int g(D) { return 2; } |
| |
| void other_main() { |
| static_assert(f<int>() == 2); |
| } |
| } // namespace |
| |
| namespace { |
| struct S { |
| int a,b,c; |
| }; |
| |
| clsss S2 { // expected-error{{{unknown type name 'clsss'}}} |
| public: |
| int a,b,c; |
| }; |
| |
| // Should not crash. |
| auto X = [] <typename = void> () { |
| auto [...pack,a,b,c] = S{}; |
| auto [x,y,z,...pack2] = S{}; |
| auto [...pack3] = S2{}; |
| static_assert(sizeof...(pack3) == 5); |
| }; |
| } // namespace |
| |
| namespace GH125165 { |
| |
| template <typename = void> |
| auto f(auto t) { |
| const auto& [...pack] = t; |
| // expected-error@-1 {{cannot decompose non-class, non-array type 'char const'}} |
| (pack, ...); |
| }; |
| |
| void g() { |
| f('x'); // expected-note {{in instantiation}} |
| } |
| |
| } |