Implement P0217R3 - C++17 structured bindings

Implement P0217R3 - C++17 structured bindings
	* g++.dg/cpp1z/decomp1.C: New test.
	* g++.dg/cpp1z/decomp2.C: New test.
	* g++.dg/cpp1z/decomp3.C: New test.
	* g++.dg/cpp1z/decomp4.C: New test.
	* g++.dg/cpp1z/decomp5.C: New test.
	* g++.dg/cpp1z/decomp6.C: New test.
	* g++.dg/cpp1z/decomp7.C: New test.
	* g++.dg/cpp1z/decomp8.C: New test.
	* g++.dg/cpp1z/decomp9.C: New test.
	* g++.dg/cpp1z/decomp10.C: New test.

Co-Authored-By: Jason Merrill <jason@redhat.com>

From-SVN: r242378
This commit is contained in:
Jakub Jelinek 2016-11-14 08:54:50 +01:00 committed by Jakub Jelinek
parent 70f40fea6a
commit 5230c3d825
11 changed files with 577 additions and 0 deletions

View File

@ -1,3 +1,18 @@
2016-11-14 Jakub Jelinek <jakub@redhat.com>
Jason Merrill <jason@redhat.com>
Implement P0217R3 - C++17 structured bindings
* g++.dg/cpp1z/decomp1.C: New test.
* g++.dg/cpp1z/decomp2.C: New test.
* g++.dg/cpp1z/decomp3.C: New test.
* g++.dg/cpp1z/decomp4.C: New test.
* g++.dg/cpp1z/decomp5.C: New test.
* g++.dg/cpp1z/decomp6.C: New test.
* g++.dg/cpp1z/decomp7.C: New test.
* g++.dg/cpp1z/decomp8.C: New test.
* g++.dg/cpp1z/decomp9.C: New test.
* g++.dg/cpp1z/decomp10.C: New test.
2016-11-13 Kugan Vivekanandarajah <kuganv@linaro.org>
* g++.dg/torture/pr78268.C: New test.

View File

@ -0,0 +1,35 @@
// { dg-do run { target c++11 } }
// { dg-options "" }
int a[2] = { 1, 2 };
struct S { int a; signed char b; float c; } s = { 6, 7, 8.0f };
int
main ()
{
auto & [ c, d ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ e, f ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ g, h, i ] = s; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto & [ j, k, l ] = s; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
c++;
d++;
e += 6;
f += 7;
g++;
h++;
j += 10;
k += 11;
if (c != 2 || &c != &a[0]
|| d != 3 || &d != &a[1]
|| e != 7 || &e == &a[0]
|| f != 9 || &f == &a[1]
|| g != 7 || &g == &s.a
|| h != 8 || &h == &s.b
|| i != 8.0f || &i == &s.c
|| j != 16 || &j != &s.a
|| k != 18 || &k != &s.b
|| l != 8.0f || &l != &s.c
|| a[0] != 2 || a[1] != 3
|| s.a != 16 || s.b != 18 || s.c != 8.0f)
__builtin_abort ();
}

View File

@ -0,0 +1,48 @@
// { dg-options -std=c++1z }
namespace std {
template<typename T> struct tuple_size;
template<int, typename> struct tuple_element;
}
struct A1 { int i,j; } a1;
template<> struct std::tuple_size<A1> { };
void f1() { auto [ x ] = a1; } // { dg-error "decomposes into 2" }
struct A2 { int i,j; } a2;
template<> struct std::tuple_size<A2> { enum { value = 5 }; };
void f2() { auto [ x ] = a2; } // { dg-error "decomposes into 5" }
struct A3 { int i,j; } a3;
template<> struct std::tuple_size<A3> { enum { value = 1 }; };
void f3() { auto [ x ] = a3; } // { dg-error "get" }
struct A3a { int i,j; int get(); } a3a;
template<> struct std::tuple_size<A3a> { enum { value = 1 }; };
void f3a() { auto [ x ] = a3a; } // { dg-error "get<0>" }
struct A3b { int i,j; } a3b;
int get(A3b&&);
template<> struct std::tuple_size<A3b> { enum { value = 1 }; };
void f3b() { auto [ x ] = a3b; } // { dg-error "get<0>" }
struct A4 {
int ar[3];
template <int I> int& get() { return ar[I]; }
} a4;
template<> struct std::tuple_size<A4> { enum { value = 3 }; };
template <int I>
void f4() { auto [ x, y, z ] = a4; } // { dg-error "tuple_element" }
struct A5 { } a5;
template <int I> int& get(A5&& a);
template<> struct std::tuple_size<A5> { enum { value = 3 }; };
template <int I>
void f5() { auto [ x, y, z ] = a5; } // { dg-error "tuple_element" }
struct A6 { } a6;
template <int I> int& get(A6&& a);
template<> struct std::tuple_size<A6> { enum { value = 3 }; };
template<> struct std::tuple_element<0, A6> { };
template <int I>
void f6() { auto [ x, y, z ] = a6; } // { dg-error "no type named .type" }

View File

@ -0,0 +1,54 @@
// { dg-do run { target c++11 } }
// { dg-options "" }
typedef int V __attribute__((vector_size (4 * sizeof (int))));
V a = (V) { 1, 2, 3, 4 };
__complex__ double b = 5.0 + 6.0i;
__complex__ int c = 7 + 8i;
int
main ()
{
auto & [ d, e, f, g ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ h, i, j, k ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ l, m ] = b; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto & [ n, o ] = b; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto & [ p, q ] = c; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ r, s ] = c; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
d += 10;
e += 11;
f += 12;
g += 13;
h += 14;
i += 15;
j += 16;
k += 17;
l = l * 2.;
m = m * 3.;
n = n * 3.;
o = o * 2.;
p += 18;
q += 19;
r += 22;
s += 23;
if (d != 11 || &d != &a[0]
|| e != 13 || &e != &a[1]
|| f != 15 || &f != &a[2]
|| g != 17 || &g != &a[3]
|| h != 15 || &h == &a[0]
|| i != 17 || &i == &a[1]
|| j != 19 || &j == &a[2]
|| k != 21 || &k == &a[3]
|| l != 10.0 || &l == &__real__ b
|| m != 18.0 || &m == &__imag__ b
|| n != 15.0 || &n != &__real__ b
|| o != 12.0 || &o != &__imag__ b
|| p != 25 || &p != &__real__ c
|| q != 27 || &q != &__imag__ c
|| r != 29 || &r == &__real__ c
|| s != 31 || &s == &__imag__ c
|| a[0] != 11 || a[1] != 13 || a[2] != 15 || a[3] != 17
|| b != 15.0 + 12.0i
|| c != 25 + 27i)
__builtin_abort ();
}

View File

@ -0,0 +1,66 @@
// { dg-do compile { target c++11 } }
// { dg-options "" }
struct A { int a, b; float c; };
A &bar ();
struct B { int d; };
B baz ();
void
test (A &b, B c)
{
int && [ d ] = c; // { dg-error "decomposition declaration cannot be declared with type 'int'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
char & [ e, f, ff ] { b }; // { dg-error "decomposition declaration cannot be declared with type 'char'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto&[g,h,i]=b; // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
decltype (auto) [ j ] = c; // { dg-error "decomposition declaration cannot be declared with type 'decltype.auto.'" "" { target c++14 } }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
// { dg-error "expected primary-expression before 'decltype'" "" { target c++11_down } .-2 }
auto & & && & [ m, n, o ] = b; // { dg-error "multiple ref-qualifiers" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
constexpr auto [ p ] = c; // { dg-error "decomposition declaration cannot be declared 'constexpr'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
friend auto [ q ] = c; // { dg-error "'friend' used outside of class" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
typedef auto [ r ] = c; // { dg-error "decomposition declaration cannot be declared 'typedef'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
inline auto [ s ] = c; // { dg-error "decomposition declaration cannot be declared 'inline'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
__restrict auto [ t ] = c; // { dg-error "invalid use of 'restrict'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
long long auto [ u ] = c; // { dg-error "'long long' invalid for 'decomposition'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
virtual auto [ v ] = c; // { dg-error "'virtual' outside class declaration" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
explicit auto [ w ] = c; // { dg-error "'explicit' outside class declaration" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
static auto [ x ] = c; // { dg-error "decomposition declaration cannot be declared 'static'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
extern auto [ y ] { c }; // { dg-error "decomposition declaration cannot be declared 'extern'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
}
void
test2 (auto & [ p ] = bar ()) // { dg-error "'p' was not declared in this scope" }
{
}
int arr[4];
void
test3 (A &b, B c)
{
auto [ d, e, f ] = arr; // { dg-error "only 3 names provided while 'int .4.' decomposes into 4 elements" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto & [ g, h, i, j, k ] = arr; // { dg-error "5 names provided while 'int .4.' decomposes into 4 elements" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ l, m ] = b; // { dg-error "only 2 names provided while 'A' decomposes into 3 elements" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto & [ n, o, p, q ] = b; // { dg-error "4 names provided while 'A' decomposes into 3 elements" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [] { c }; // { dg-error "empty decomposition declaration" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ r, s ] = c; // { dg-error "2 names provided while 'B' decomposes into 1 elements" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
}

View File

@ -0,0 +1,32 @@
// { dg-do compile { target c++11 } }
// { dg-options "" }
struct A { int a; struct { int b; }; };
struct B { int a; union { int c; long d; }; };
struct C { int a; private: int b; };
struct D { int a; private: static int b; };
struct E { protected: int a; };
struct F { int a; };
struct G : public F { int b; };
struct H { int b; };
struct I : public F, H {};
void
test (A &a, B &b, C &c, D &d, E &e, F &f, G &g, H &h, I &i)
{
auto [ j ] = a; // { dg-error "cannot decompose class type 'A' because it has an anonymous struct member" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ k ] { b }; // { dg-error "cannot decompose class type 'B' because it has an anonymous union member" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ l ] = c; // { dg-error "cannot decompose non-public member 'C::b' of 'C'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ m ] = d; // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
auto [ n ] { e }; // { dg-error "cannot decompose non-public member 'E::a' of 'E'" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ o ] { f }; // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
auto & [ p ] { g }; // { dg-error "cannot decompose class type 'G': both it and its base class 'F' have non-static data members" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
auto [ q ] { h }; // { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } }
auto [ r ] { i }; // { dg-error "cannot decompose class type 'I': its base classes 'F' and 'H' have non-static data members" }
// { dg-warning "decomposition declaration only available with -std=c..1z or -std=gnu..1z" "" { target c++14_down } .-1 }
}

View File

@ -0,0 +1,40 @@
// { dg-do run { target c++11 } }
// { dg-options "" }
struct A { int i; long long j; } a[64];
int
main ()
{
int i = 0;
for (auto &x : a)
{
x.i = i;
x.j = 2 * i++;
}
for (auto & [ x, y ] : a) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
x += 2;
y += 3;
}
i = 0;
for (const auto [ u, v ] : a) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
if (u != i + 2 || v != 2 * i++ + 3)
__builtin_abort ();
}
i = 0;
for (auto [ x, y ] : a) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
x += 4;
y += 5;
if (x != i + 6 || y != 2 * i++ + 8)
__builtin_abort ();
}
i = 0;
for (const auto x : a)
{
if (x.i != i + 2 || x.j != 2 * i++ + 3)
__builtin_abort ();
}
}

View File

@ -0,0 +1,92 @@
// { dg-do run { target c++11 } }
// { dg-options "" }
int ccnt, dcnt, cccnt, tccnt;
struct A
{
A () : a (6) { ccnt++; }
~A () { dcnt++; }
explicit A (const A &x) : a (x.a) { cccnt++; }
template <typename T>
A (const T &x) : a (x.a) { tccnt++; }
int a;
};
int
main ()
{
if (ccnt || dcnt || cccnt || tccnt)
__builtin_abort ();
{
A a[6];
if (ccnt != 6 || dcnt || cccnt || tccnt)
__builtin_abort ();
{
auto [b,c,d,e,f,g] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
__builtin_abort ();
b.a++;
c.a += 2;
f.a += 3;
if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
__builtin_abort ();
if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
__builtin_abort ();
{
auto&[ h, i, j, k, l, m ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
__builtin_abort ();
j.a += 4;
k.a += 5;
m.a += 6;
if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || a[4].a != 6 || a[5].a != 12)
__builtin_abort ();
if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != &a[4] || &m != &a[5])
__builtin_abort ();
}
if (ccnt != 6 || dcnt || cccnt || tccnt != 6)
__builtin_abort ();
}
if (ccnt != 6 || dcnt != 6 || cccnt || tccnt != 6)
__builtin_abort ();
}
if (ccnt != 6 || dcnt != 12 || cccnt || tccnt != 6)
__builtin_abort ();
{
A a[6];
if (ccnt != 12 || dcnt != 12 || cccnt || tccnt != 6)
__builtin_abort ();
{
auto [b,c,d,e,f,g] { a }; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
b.a++;
c.a += 2;
f.a += 3;
if (b.a != 7 || c.a != 8 || d.a != 6 || e.a != 6 || f.a != 9 || g.a != 6)
__builtin_abort ();
if (&b == &a[0] || &c == &a[1] || &d == &a[2] || &e == &a[3] || &f == &a[4] || &g == &a[5])
__builtin_abort ();
{
auto&[ h, i, j, k, l, m ] {a}; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
j.a += 4;
k.a += 5;
m.a += 6;
if (a[0].a != 6 || a[1].a != 6 || a[2].a != 10 || a[3].a != 11 || a[4].a != 6 || a[5].a != 12)
__builtin_abort ();
if (&h != &a[0] || &i != &a[1] || &j != &a[2] || &k != &a[3] || &l != &a[4] || &m != &a[5])
__builtin_abort ();
}
if (ccnt != 12 || dcnt != 12 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
}
if (ccnt != 12 || dcnt != 18 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
}
if (ccnt != 12 || dcnt != 24 || cccnt != 6 || tccnt != 6)
__builtin_abort ();
}

View File

@ -0,0 +1,60 @@
// { dg-do run { target c++11 } }
// { dg-options "" }
int a[2] = { 1, 2 };
int b[2] = { 4, 5 };
struct S { int a; signed char b; float c; } sa = { 6, 7, 8.0f };
S sb = { 9, 10, 11.0f };
template <typename T, typename U>
void
foo (T &x, U &y)
{
auto & [ c, d ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ e, f ] = a; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ g, h, i ] = sa; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto & [ j, k, l ] = sa; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto & [ m, n ] = x; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ o, p ] = x; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto [ q, r, s ] = y; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
auto & [ t, u, v ] = y; // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
c += 1;
e += 2;
g += 3;
j += 4;
m += 5;
o += 6;
q += 7;
t += 8;
if (c != 2 || &c != &a[0]
|| d != 2 || &d != &a[1]
|| e != 3 || &e == &a[0]
|| f != 2 || &f == &a[1]
|| g != 9 || &g == &sa.a
|| h != 7 || &h == &sa.b
|| i != 8.0f || &i == &sa.c
|| j != 10 || &j != &sa.a
|| k != 7 || &k != &sa.b
|| l != 8.0f || &l != &sa.c
|| m != 9 || &m != &b[0]
|| n != 5 || &n != &b[1]
|| o != 10 || &o == &b[0]
|| p != 5 || &p == &b[1]
|| q != 16 || &q == &sb.a
|| r != 10 || &r == &sb.b
|| s != 11.0f || &s == &sb.c
|| t != 17 || &t != &sb.a
|| u != 10 || &u != &sb.b
|| v != 11.0f || &v != &sb.c
|| a[0] != 2 || a[1] != 2
|| sa.a != 10 || sa.b != 7 || sa.c != 8.0f
|| b[0] != 9 || b[1] != 5
|| sb.a != 17 || sb.b != 10 || sb.c != 11.0f)
__builtin_abort ();
}
int
main ()
{
foo (b, sb);
}

View File

@ -0,0 +1,88 @@
// { dg-do run { target c++11 } }
// { dg-options "" }
struct A { int i; long long j; } a[64];
A b[32];
template <typename T>
void
foo (T &b)
{
int i = 0;
for (auto &x : a)
{
x.i = i;
x.j = 2 * i++;
}
for (auto & [ x, y ] : a) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
x += 2;
y += 3;
}
i = 0;
for (const auto [ u, v ] : a) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
if (u != i + 2 || v != 2 * i++ + 3)
__builtin_abort ();
}
i = 0;
for (auto [ x, y ] : a) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
x += 4;
y += 5;
if (x != i + 6 || y != 2 * i++ + 8)
__builtin_abort ();
}
i = 0;
for (const auto x : a)
{
if (x.i != i + 2 || x.j != 2 * i++ + 3)
__builtin_abort ();
}
i = 0;
for (auto &x : b)
{
x.i = i;
x.j = 2 * i++;
}
for (auto & [ x, y ] : b) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
x -= 2;
y -= 3;
}
i = 0;
for (const auto [ u, v ] : b) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
if (u != i - 2 || v != 2 * i++ - 3)
__builtin_abort ();
}
i = 0;
for (auto [ x, y ] : b) // { dg-warning "decomposition declaration only available with" "" { target c++14_down } }
{
x -= 4;
y -= 5;
if (x != i - 6 || y != 2 * i++ - 8)
__builtin_abort ();
}
i = 0;
for (const auto x : b)
{
if (x.i != i - 2 || x.j != 2 * i++ - 3)
__builtin_abort ();
}
}
int
main ()
{
foo (b);
for (int i = 0; i < 64; i++)
{
if (a[i].i != i + 2 || a[i].j != 2 * i + 3)
__builtin_abort ();
if (i >= 32)
continue;
if (b[i].i != i - 2 || b[i].j != 2 * i - 3)
__builtin_abort ();
}
}

View File

@ -0,0 +1,47 @@
// { dg-do run }
// { dg-options -std=c++1z }
#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
namespace std {
template<typename T> struct tuple_size;
template<int, typename> struct tuple_element;
}
struct A {
int i;
template <int I> int& get() { return i; }
};
template<> struct std::tuple_size<A> { static const int value = 2; };
template<int I> struct std::tuple_element<I,A> { using type = int; };
struct B {
int i;
};
template <int I> int& get(B&& b) { return b.i; }
template <int I> int& get(B& b) { return b.i; }
template<> struct std::tuple_size<B> { static const int value = 2; };
template<int I> struct std::tuple_element<I,B> { using type = int; };
int main()
{
{
A a = { 42 };
auto& [ x, y ] = a;
assert (&x == &y && &x == &a.i && x == 42);
auto [ x2, y2 ] = a;
assert (&x2 == &y2 && &x2 != &a.i && x2 == 42);
}
{
B b = { 42 };
auto& [ x, y ] = b;
assert (&x == &y && &x == &b.i && x == 42);
auto [ x2, y2 ] = b;
assert (&x2 == &y2 && &x2 != &b.i && x2 == 42);
}
}