如何为一个班级提供多个开始/结束代理 [英] How to provide multiple begin/end proxies for a class

查看:68
本文介绍了如何为一个班级提供多个开始/结束代理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给班上

struct Data
{
  void bar() const;
  void baz();
}

class Foo
{
  std::vector<Data> data;
  std::map<size_t, Data> indexed_data;
}

我想在Foo类中实现一些东西,以便可以执行以下操作:

I'd like to implement something in class Foo so that I can do the following:

int main()
{
  Foo foo;

  for(const auto& data : foo.data())
    data.bar();

  for(auto& data : foo.indexed_data())
    data.baz();

  const auto& foo_ref = foo;
  for(auto& data : foo_ref.data())
    data.baz();  // constness violated, shouldn't compile
}

但是,我不想仅通过返回对容器的引用来公开类的内部.我可能还会使用那些我想迭代的范围未实现为容器的类.因此,我基本上想创建某种代理对象,该对象只不过是对开始/结束对的包装,因此我可以遍历类中的多个内容. 另外,我希望它如上所示是const正确的.有没有众所周知的模式可以实现这一目标?

However, I don't wanna expose the class internals by just returning references to the containers. I might also work with classes where the range I'd like to iterate over isn't implemented as a container. So I basically want to create some sort of proxy object which is just a little more than a wrapper to a begin/end pair so that I can iterate over multiple things inside my class. Additionally I would like it to be const correct as displayed above. Is there any well-known pattern to realize this?

推荐答案

请考虑三种情况.

如果您想完全访问内部数据,只需创建一个函数即可将其返回:(只需公开成员也是一种选择)

If you want to give full access to your internal data, just make a function to return it: (simply making the member public is also an option)

class C {
public:
          Type& data()       { return data_; }
    const Type& data() const { return data_; }
private:
    Type data_;
};


如果要授予对内部数据的只读访问权限,只需删除非const重载即可:


If you want to give read-only access to your internal data, just drop the non-const overload:

class C {
public:
    const Type& data() const { return data_; }
private:
    Type data_;
};


如果您要仅对内部数据授予仅元素访问权限,即,您可以对每个单独的元素进行可变访问(当C本身为非常量时),但是您不能更改容器本身(例如,插入一个新元素),则需要返回一个代理.从C ++ 20开始,我们可以返回std::ranges::ref_view:


If you want to give element-only access to your internal data, i.e., you have mutable access to each individual element (when the C itself is non-const), but you can't change the container itself (e.g., insert a new element), you need to return a proxy. Since C++20, we can return a std::ranges::ref_view:

class C {
public:
    auto data()       { return std::ranges::ref_view(data_); }
    auto data() const { return std::ranges::ref_view(data_); }
private:
    Type data_;
};

如果C ++ 20不可用,则可以使用范围库.这样,用户可以访问各个元素,但不能更改容器本身.

You can use the Ranges library if C++20 is not available. This way, the user can access the individual elements, but cannot change the container itself.

或者,您可以编写自己的(最低限度的)代理服务器:

Alternatively, you can write your own (minimalist) proxy:

template <typename R>
class Proxy {
public:
    explicit Proxy(R& r) :range{r} {}
    auto begin() const { return range.begin(); }
    auto   end() const { return range.end(); }
private:
    R& range;
};

然后您可以返回Proxy{data_}:

class C {
public:
    auto data()       { return Proxy{data_}; }
    auto data() const { return Proxy{data_}; }
private:
    Type data_;
};

在C ++ 17之前,您可以像这样编写它,而无需扣除类模板参数:

Prior to C++17, you can write it like this without class template argument deduction:

class C {
public:
    auto data()       { return Proxy<      Type>{data_}; }
    auto data() const { return Proxy<const Type>{data_}; }
private:
    Type data_;
};

这篇关于如何为一个班级提供多个开始/结束代理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆