您自己的类型的结构化绑定不是结构或元组(通过 public 成员函数)

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

我正在浏览 Herb Sutter 的

旅程:走向更强大、更简单的 C++ 编程

Structure Binding

为了理解这个概念。最好是写一个我试过但出现错误的程序

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;
}

错误

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

需要帮助

1.If 任何人都可以详细说明他实际上在这些方面试图做什么 (请参考提供的link)

// 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 建议如何修复上述示例的错误

修复 Sutter 示例中的错误

我认为这是 Herb Sutter 博客 typo/glitch 中的一个 post:他应该让那些成员 public,或者为他们提供 getter,或者让 std::get()函数一个朋友。

此外,Herb 似乎忘记在函数签名中加入 "x"...

get函数的解释

您引用的函数类似于 std::get() 对元组的作用。如果我有

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

然后

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

而在 Herb 的例子中,他需要为 S class 做同样的工作,即 std::get<0>(s) return [=18= 的第一个成员], std::get<1>(s) return 第二个成员等。这是必要的,因为否则,您不能使用 S 来初始化结构化绑定。

Hebr 实现中的 "magic" 是他 return 从其函数的不同点获取不同类型的值。这个"magic"是一个if constexpr的效果。从本质上讲,这意味着编译器会忽略除不相关分支的语法之外的所有内容。所以对于I = 0,函数是:

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;
   */
}

对于 I = 1 它是

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; */
   }
}

等然后 auto 选择合适的类型。

这里有很多问题。

首先,为了符合结构化绑定的条件,您需要专门化 tuple_size:

namespace std {
    template <> struct tuple_size<foobar> : std::integral_constant<size_t, 2> { };
}

接下来,您的 tuple_element 专业也必须在 namespace std:

namespace std {
    template <> struct tuple_size<foobar> : std::integral_constant<size_t, 2> { };

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

接下来,如果您要像往常一样访问私有成员,则必须将 get 声明为 friend 函数:

class foobar {
    template <int I> friend auto get(foobar const& );
};

最后,get() 确实有更好的 return 参考,否则你的绑定最终会做出令人惊讶的事情:

template<int I>
auto const& get(const foobar&x) {
    if      constexpr(I == 0) return x._ival;
    else if constexpr(I == 1) return x.s;
}

与其处理 friendship,不如让 get() 成为 public 成员,然后编写您需要的三个重载:

class foobar {
public:
    template <size_t I>
    auto& get() & {
        if constexpr (I == 0) return _ival;
        else if constexpr (I == 1) return s;
    }

    template <size_t I>
    auto const& get() const& {
        if constexpr (I == 0) return _ival;
        else if constexpr (I == 1) return s;
    }

    template <size_t I>
    auto&& get() && {
        if constexpr (I == 0) return std::move(_ival);
        else if constexpr (I == 1) return std::move(s);
    }
};

另外 ival() 作为一个函数没有意义。你的构造函数应该只接受参数。