Search code examples
c++c++17stdtuplestructured-bindingsif-constexpr

Structured bindings for your own type that isn’t a struct or a tuple(via public member function)


I am going through the Herb Sutter's

A journey: Toward more powerful and simpler C++ programming

Structure Binding section

In order to understand the concept .Best is to write a program I tried but getting some error

Just want to try how to use structure binding on class with private data .Please ignore the below example.if any example you can provide

#include<iostream>
#include<string>
using namespace std;

class foobar {
public:
    foobar() { cout << "foobar::foobar()\n"; }
    ~foobar() { cout << "foobar::~foobar()\n"; }

    foobar( const foobar &rhs )
    { cout << "foobar::foobar( const foobar & )\n"; }
    void ival( int nval, string new_string ) { _ival = nval;s=new_string; }

private:
    int _ival;
    string s;
};

foobar f( int val,string new_string ) {
    foobar local;
    local.ival( val,new_string );
    return local;
}

template<> struct tuple_element<0,foobar> { using type = int; };
template<> struct tuple_element<1,foobar> { using type = string; };



 // 2. Now add get<> support (using C++17, because why not; it’s better
 // than =delete’ing the primary get<> template and adding specializations)
 template<int I>
 auto get(const foobar&x) {
 if      constexpr(I == 0) return x._ival;//'_ival' is a private member of 'foobar'
 else if constexpr(I == 1) return x.s;//'s' is a private member of 'foobar'
 }


int main(){
    foobar ml = f( 1024,"hello" );
    auto [ n, s] = f( 1024,"hello" );//Cannot decompose non-public member '_ival' o
    return 0;
}

Error

if constexpr(I == 0) return x._ival;//'_ival' is a private member of 'foobar'

else if constexpr(I == 1) return x.s;//'s' is a private member of 'foobar'

auto [ n, s] = f( 1024,"hello" );//Cannot decompose non-public

Help required

1.If anyone can elaborate what he is actually trying to do on these lines (please refer the link provided)

// 2. Now add get<> support (using C++17, because why not; it’s better
// than =delete’ing the primary get<> template and adding specializations)
template<int I>
auto get(const S&) {
   if      constexpr(I == 0) return x.i;
   else if constexpr(I == 1) return string_view{x.c}; }
   else if constexpr(I == 2) return x.d;
}

2.Any suggestion how to fix the error for the above example


Solution

  • Fixing the errors in Sutter's example

    I think it's a typo/glitch in Herb Sutter's blog post: He should have made those members public, or provided getters for them, or made the std::get() function a friend.

    Also, it looks like Herb forgot to put "x" in the function signature...

    Explanation of the get function

    The function you quote is similar to how std::get() works for tuples. If I have

    std::tuple<int, std::string> t;
    

    then

    auto x { std::get<0>(t) }; // x is an integer
    auto y { std::get<1>(t) }; // y is an std::string
    

    and in Herb's example, he needs to have the same work for the S class, i.e. have std::get<0>(s) return the first member of s, std::get<1>(s) return the second member etc. This is necessary, because otherwise, you can't use S for initializing a structured binding.

    The "magic" in Hebr's implementation is that he's returning values of different types from different points in his function. This "magic" is the effect of an if constexpr. It means, essentially, that the compiler ignores everything except the syntax of the irrelevant branches. So for I = 0, the function is:

    auto get(const S&) {
      if (true) return x.i;
      /* else if constexpr(I == 1) return string_view{x.c}; 
         else if constexpr(I == 2) return x.d;
       */
    }
    

    for I = 1 it's

    template<int I>
    auto get(const S&) {
       if      (false) {/* return x.i; */ ; }
       else if (true) return string_view{x.c};
       /* else if constexpr(I == 2) return x.d; */
       }
    }
    

    etc. And the auto chooses the appropriate type.