c++ - 结构绑定(bind) : binding to public data members (inherited base class )

标签 c++ c++17

即使基类和派生类都有公共(public)数据成员

#include <iostream>
class M {
    public:
    int x = 2;
    volatile double y=3;
};

class S:public M {
    public:
    int x1 = 4 ;
    volatile double y1 = 5;

};

int main() {
    S f();
    S a;
    std::cout<<a.x<<a.y<<a.x1<<a.y1;
    auto [b,c,d,e] = f(); 
}

获取错误

 auto [b,c,d,e] = f(); 

main.cpp: In function 'int main()': main.cpp:21:10: error: cannot decompose class type 'S': both it and its base class 'M' have non-static data members auto [b,c,d,e] = f();

根据 http://en.cppreference.com/w/cpp/language/structured_binding

案例 3:绑定(bind)到公共(public)数据成员

E 的每个非静态数据成员都必须是 E 的公共(public)直接成员或 E 的相同的明确公共(public)基础

不明白这是什么意思 E 的相同明确公共(public)基础

DEMO

最佳答案

这里有三个形容词,分别规定了三个正交的要求:

  1. 相同
  2. 明确
  3. 公开

按顺序,查看反例可能会有所帮助。在所有情况下,假设 template <class T> T make();存在。


“相同”的反例:D 有两个成员, 但他们不是 D 的同一基地的成员- iB 的成员但是jD 的成员:

struct B { int i; };
struct D : B { int j; };

auto [i, j] = make<D>(); // error

要解决此问题,j需要是B的直接成员或 i需要是D的直接成员:

struct B { int i, j; };
struct D : B { };
auto [i, j] = make<D>(); // ok

struct B { };
struct D : B { int i, j; };
auto [i, j] = make<D>(); // ok

“明确”的反例:D 有两个成员, 他们都是 B 的成员, 但它是 D 的不明确基类.

struct B { int i; };
struct M1 : B { };
struct M2 : B { };
struct D : M1, M2 { };

auto [i, j] = make<D>(); // error

如果Bvirtual两者的基础M1M2 ,那么这样就可以了:

struct B { int i; };
struct M1 : virtual B { };
struct M2 : virtual B { };
struct D : M1, M2 { };

auto [i] = make<D>(); // ok

“公共(public)”的反例。这是最简单的一个。如果成员在私有(private)基地中,则无论如何都无法访问他们:

struct B { int i; };
struct D : private B { };

make<D>().i;          // error, as-is
auto [i] = make<D>(); // error, non-public base, but really same reason

另请注意,正如 TC 指出的那样,要求是base 是公开的,而不是成员可访问。也就是说,让成员可以从私有(private)库访问仍然行不通:

struct B { int i; };
struct D : private B { using B::i; };

make<D>().i;        // ok now, due to the using-declaration
auto [i] = make<D>(); // still error, B is still private base

当然,在所有这些反例案例中,只是因为所有成员都不在 E 的同一个、明确的公共(public)基类中。并不意味着它不能用于结构化绑定(bind)。这只是意味着你必须自己写出绑定(bind):

struct B { int i; };
struct D : B { int j; };

namespace std {
    template <> struct tuple_size<D> : std::integral_constant<int, 2> { };
    template <size_t I> struct tuple_element<I, D> { using type = int; };
}

template <size_t I>
int& get(D& d) {
    if constexpr (I == 0) { return d.i; }
    else                  { return d.j; }
}

template <size_t I>
int const& get(D const& d) {
    if constexpr (I == 0) { return d.i; }
    else                  { return d.j; }
}

template <size_t I>
int&& get(D&& d) {
    if constexpr (I == 0) { return std::move(d).i; }
    else                  { return std::move(d).j; }
}

auto [i,j] = make<D>(); // now ok: we're in case 2 instead of 3

关于c++ - 结构绑定(bind) : binding to public data members (inherited base class ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46003652/

相关文章:

c++ - std::shared_ptr 迭代器

c++ - 使用前导和尾随空格 boost spirit 解析字符串

c++ - 尽管文件确实存在,std::filesystem::exists() 返回 false

c++ - 使用折叠表达式为数组实现 less 运算符

c++ - 保证非 odr 使用的全局变量的延迟动态初始化

c++ - 按值返回时不调用复制构造函数

c++ - MFC C++ 从 CEdit 派生并派生 GetWindowText

c++ - QT 使用 QNetworkAccessManager 下载文件

c++ - 禁止转换为父级,但公开父级的接口(interface)(设计问题)

c++ - bool 内存高效链表