Orient Orient - 2 months ago 27
C++ Question

Structured bindings implementation underground and std::tuple

Is it true, that structured bindings in

clang
(I use recently builded
clang version 4.0.0 (trunk 282683)
) are implemented using some stuff from
<tuple>
, like braces-init lists may use stuff from
<initializer_list>
?

I wrote simple code just to play with some of latest features implemented:

struct S { int a; char b; double c; };
auto [a, b, c] = S{1, '2', 3.0};
using A = decltype(a);
using A = int;
using B = decltype(b);
using B = char;
using C = decltype(c);
using C = double;


So far so good, but when I add
const
qualifier before
auto
:

struct S { int a; char b; double c; };
const auto [a, b, c] = S{1, '2', 3.0};
using A = decltype(a);
using A = int const;
using B = decltype(b);
using B = char const;
using C = decltype(c);
using C = double const;


I get a strange error description:

In file included from /home/user/test/main.cpp:1:
In file included from /home/user/test/./test.hpp:4:
In file included from /usr/local/bin/../include/c++/v1/utility:193:
/usr/local/bin/../include/c++/v1/__tuple:29:14: fatal error: implicit instantiation of undefined template 'std::__1::tuple_size<S>'
: public tuple_size<_Tp> {};
^
/home/user/test/main.cpp:110:16: note: in instantiation of template class 'std::__1::tuple_size<const S>' requested here
const auto [a, b, c] = S{1, '2', 3.0};
^
/usr/local/bin/../include/c++/v1/__tuple:25:50: note: template is declared here
template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size;
^


I.e. there is interaction with accidentally included
<tuple>
.

I know that structured bindings are partially implemented in
clang
, but either way it is interesting how
<tuple>
may be related to them?

Should I include
<tuple>
to use structured bindings?

Additional:



auto
,
auto &
and
auto &&
works, but
auto const
and
auto const &
not.

Answer

Yes, structured binding uses tuple_size and tuple_element as customization points. The basic rule is, roughly,

  1. first handle built-in arrays;
  2. then check tuple_size<T>::value;
  3. if that fails then check if the class has all public data members.

For step #2 to work reliably, tuple_size needs to be SFINAE-friendly, but tuple_size<cv T> isn't currently required to be SFINAE-friendly. Hence the bug.