5

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.

Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169
  • Implemenation using `std::tie` would be kind of natural to me... – W.F. Sep 29 '16 at 07:13
  • 1
    @W.F. Another way is to make the feature built-in. – Tomilov Anatoliy Sep 29 '16 at 07:14
  • I mean underlying implemenation :) but I know it doesn't answer your question... – W.F. Sep 29 '16 at 07:16
  • 2
    See [LWG 2770](http://wg21.link/LWG2770). You can expect this to be fixed before C++17 ships. – T.C. Sep 29 '16 at 08:04
  • 1
    @W.F. `tie` would be utterly unnatural to me, but whatever. – T.C. Sep 29 '16 at 08:10
  • @T.C. got your point... thanks – W.F. Sep 29 '16 at 09:11
  • I'm trying to get this to work myself, I'm using `Apple LLVM version 8.0.0 (clang-800.0.38)`, so clang 8? You said clang 4, what does that mean? I cannot get structured bindings to compile at all. Can you indicate how you got clang to compile this (I've got the makefile set to C++1z) – johnbakers Oct 06 '16 at 13:36
  • @johnbakers `clang --version | head -1` give `clang version 4.0.0 (trunk 282862)` at the moment – Tomilov Anatoliy Oct 06 '16 at 14:24
  • @johnbakers on *Ubuntu 16.04* append next two lines to `/etc/apt/sources.list`: `deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial main` `deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial main`. Then `apt-get update`. Then `apt-get install clang-4.0`. – Tomilov Anatoliy Oct 06 '16 at 14:27
  • @johnbakers Another way is to build `clang` from trunk by yourself. [Here](http://stackoverflow.com/questions/39716684/) I wrote an algorithm (it can be reduced to the first couple of bullets for your case). – Tomilov Anatoliy Oct 06 '16 at 14:29
  • thanks for the pointers (no pun intended!) – johnbakers Oct 06 '16 at 14:29

1 Answers1

7

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Interesting how looks like an equivalent (pseudo)code (like one exsistent for ranged *for*-loop) of such a SFINAE-based algorithm. Why if `` is not included, there is no hard error here? It's strange. Because if there is no symbol `std::tuple_size` then there definitely should be hard error here but it is not the case. Whereas violation of SFINAE-friendlieness of `tuple_size` gives hard error. – Tomilov Anatoliy Sep 29 '16 at 09:40
  • @Orient It's a special core language construct; it doesn't have to obey (normal) SFINAE rules. And arguably not triggering a hard error on missing `tuple_size` makes sense because freestanding implementations need not have `tuple_size` at all. – T.C. Sep 29 '16 at 19:37