c++ - 如何为一个类提供多个开始/结束代理

标签 c++ iterator range c++14 const-correctness

给定类

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

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

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

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 正确的。有什么众所周知的模式可以实现这一点吗?

最佳答案

考虑三种情况。


如果您想授予对内部数据的完全访问权限,只需创建一个函数来返回它:(简单地公开成员也是一种选择)

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

如果您想授予对内部数据的只读访问权限,只需删除非常量重载:

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

如果你想授予对内部数据的仅元素访问权限,即你对每个单独的元素具有可变访问权限(当 C 本身是非常量时),但你不能改变容器本身(例如,插入一个新元素),你需要返回一个代理。从 C++20 开始,我们可以返回一个 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_;
};

您可以使用 Ranges library如果 C++20 不可用。这样,用户可以访问各个元素,但不能更改容器本身。

或者,您可以编写自己的(极简主义)代理:

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之前,你可以这样写而无需类模板参数推导:

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

关于c++ - 如何为一个类提供多个开始/结束代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57152866/

相关文章:

javascript - 如何在 javascript 中保存和恢复选择范围?

c++ - 邮件大小限制似乎比开放MPI中的要小得多

c++ - 在 else block 中和 if block 之后执行代码

c++ - 使用struct c++读取压缩文件Gzread

c++ - 递增迭代器 C++

php - 将 md5(或者可能是另一种哈希方法?)转换为整数的算法,其中可以设置可能的结果整数范围(例如 : 1-10000)?

c++ - 使用 mpi 将矩阵写入单个 txt 文件

C++ 在给定位置寻找一个 std::string::iterator

c++ - 稀疏容器和迭代器

datatables - 如何使用范围日期选择器过滤服务器端 jquery 数据表