提升模拟C#的IEnumerable的方法?

时间:2014-12-30 22:28:12

标签: c++ boost stl

在C#中,我可以执行以下操作

class MyClass {
   private List<int> lst;
   public IEnumerable<int> Numbers { get { return lst; } }
}

这样可以使公众只读lst,而不会将List成员变量暴露给公众。例如,班级的用户可以写

foreach (var n in myClass.Numbers) { /* do something with the values * / };

但是他们无法更改列表或以相反的顺序遍历它。这使我有可能在不使用类破坏代码的情况下更改实现。

我想在C ++中做类似的事情:

class MyClass {
   std::vector<int> lst;
public:
   /* ???? */ getNumbers () const { return /* ??? */ lst; }
};

// I want to be able to write the following
auto rng = myClass.getNumbers ();
auto b = begin (rng);
auto e = end (rng);
// now b and e should be readonly (!) forward (!) iterators

我不关心编译时依赖性,即我不想使用any_range。但我知道 我希望在我的代码中明确表示我只保证只读前进行为。

2 个答案:

答案 0 :(得分:2)

您可以派生迭代器类型

template <typename Base>
struct const_forward_iterator : public Base {
    using base_type         = Base;
    using iterator_type     = const_forward_iterator;
    using iterator_category = std::forward_iterator_tag;

    const_forward_iterator& operator+=(typename Base::difference_type) = delete;
    const_forward_iterator& operator-=(typename Base::difference_type) = delete;
    const_forward_iterator  operator+ (typename Base::difference_type) = delete;
    const_forward_iterator  operator- (typename Base::difference_type) = delete;

    const_forward_iterator(base_type it) : base_type(it) {}
};

基于一个简单的范围

template <typename it>
struct range : std::pair<it,it> {
    range(it b, it e) : std::pair<it,it>(b,e) {}

    it begin() const { return this->first; }
    it end()   const { return this->second; }
};

利润:

using iterator_type = const_forward_iterator<std::vector<int>::const_iterator>;
range<iterator_type> getNumbers() const { return { lst.cbegin(), lst.cend() }; }

<强> Live On Coliru

#include <vector>
#include <iterator>

namespace detail {
    template <typename Base>
    struct const_forward_iterator : public Base {
        using base_type         = Base;
        using iterator_type     = const_forward_iterator;
        using iterator_category = std::forward_iterator_tag;

        const_forward_iterator& operator+=(typename Base::difference_type) = delete;
        const_forward_iterator& operator-=(typename Base::difference_type) = delete;
        const_forward_iterator  operator+ (typename Base::difference_type) = delete;
        const_forward_iterator  operator- (typename Base::difference_type) = delete;

        const_forward_iterator(base_type it) : base_type(it) {}
    };

    template <typename it>
    struct range : std::pair<it,it> {
        range(it b, it e) : std::pair<it,it>(b,e) {}

        it begin() const { return this->first; }
        it end()   const { return this->second; }
    };
}

class MyClass {
    std::vector<int> lst { 1, 3, 77, 42 };
  public:

    using iterator_type = detail::const_forward_iterator<std::vector<int>::const_iterator>;

    detail::range<iterator_type> getNumbers() const { return { lst.cbegin(), lst.cend() }; }
};

#include <iostream>

int main()
{
    MyClass o;

    for (auto i : o.getNumbers())
        std::cout << i << " ";

    auto numbers = o.getNumbers();
    //numbers.first += 2; error: use of deleted function
}

输出

1 3 77 42 

当然,您可以将代码分解为可以重用位,但这是作为一个自包含的PoC

答案 1 :(得分:1)

正如我现在发现的那样,boost::range是与IEnumerable最接近的C ++。