如何在我班上允许范围循环?

时间:2013-08-19 18:58:43

标签: c++ c++11 iterator

我有一个这样的课程:

class Foo {
private:
    int a,b,c,d;
    char bar;
    double m,n
public:
    //constructors here
};

我想在课堂上允许使用范围循环,例如

Foo foo {/*...*/};
for(auto& f : foo) {
  //f will be a specific order such as c,b,d,(int)m,(int)bar,a,(int)n
}

我怎样才能做到这一点?我在看迭代器,但不知道range-for循环的要求是什么。 (请不要让我使用数组或STL类型)

3 个答案:

答案 0 :(得分:10)

循环被定义为等同于:

for ( auto __begin = <begin-expr>,
           __end = <end-expr>;
      __begin != __end;
      ++__begin ) {
    auto& f = *__begin;
    // loop body
}

其中<begin-expr>foo.begin(),如果没有合适的成员函数则为begin(foo)<end-expr>同样为++it。 (这是C ++ 11 6.5.4中规范的简化,对于这种特殊情况,其范围是类类型的 lvalue 。)

所以你需要定义一个支持预增量*it,解除引用i1 != i2和比较foo的迭代器类型;和

  • 提供begin()个公开成员函数end()begin(foo);或
  • 在与end(foo)相同的命名空间中定义非成员函数foo和{{1}},以便通过参数依赖查找找到它们。

答案 1 :(得分:1)

这似乎相当不像C ++,而且很容易破损。如果在将来的某个更新期间更改(意外或不是)迭代顺序会怎么样?依赖特定订单的客户将会破产。

如果您希望支持这一切,那么您需要做的就是实现自己的迭代器并提供begin / end方法(或带有这些名称的自由函数)来提供访问权限。然后迭代器负责记住它当前正在查看哪个属性,并在解除引用时提供它。

答案 2 :(得分:0)

这是我提出的基本框架:

#include <iterator>

struct Foo;

template<typename Type>
struct MemberPtrBase {
    virtual ~MemberPtrBase() { }

    virtual Type get() const = 0;
    virtual MemberPtrBase & set(Type const &) = 0;
};

template<typename Class, typename RealType, typename CommonType>
struct MemberPtr : MemberPtrBase<CommonType> {
public:
    MemberPtr(Class * object, RealType(Class::*member))
    : m_object(object), m_ptr(member)
    { }

    CommonType get() const {
        return m_object->*m_ptr;
    }

    MemberPtr & set(CommonType const & val) {
        m_object->*m_ptr = val;
        return *this;
    }

    MemberPtr & operator=(RealType const & val) {
        return set(val);
    }

    operator CommonType() const {
        return get();
    }
private:
    Class * m_object;
    RealType (Class::*m_ptr);
};

template<typename Class, typename... Types>
struct MemberIterator {
public:
    using CommonType = typename std::common_type<Types...>::type;
public:
    MemberIterator(Class & obj, std::size_t idx, Types(Class::*...member))
    : m_object(obj), m_index(idx), m_members { new MemberPtr<Class, Types, CommonType>(&obj, member)... }
    { }

    MemberPtrBase<CommonType> & operator*() const {
        return *m_members[m_index];
    }

    bool operator==(MemberIterator const & it) const {
        return (&m_object == &it.m_object) && (m_index == it.m_index);
    }

    bool operator!=(MemberIterator const & it) const {
        return (&m_object != &it.m_object) || (m_index != it.m_index);
    }

    MemberIterator & operator++() {
        ++m_index;
        return *this;
    }
private:
    Class & m_object;
    std::size_t m_index;
    MemberPtrBase<CommonType> * m_members[sizeof...(Types)];
};

struct Foo {
public:
    using iterator = MemberIterator<Foo, int, int, int, int>;
public:
    Foo(int a, int b, int c, int d)
    : m_a(a), m_b(b), m_c(c), m_d(d)
    { }

    iterator begin() {
        return iterator(*this, 0, &Foo::m_b, &Foo::m_d, &Foo::m_c, &Foo::m_a);
    }

    iterator end() {
        return iterator(*this, 4, &Foo::m_b, &Foo::m_d, &Foo::m_c, &Foo::m_a);
    }
private:
    int m_a, m_b, m_c, m_d;
};

如果您对可变参数模板有基本的了解,我认为代码是不言自明的。

用法很简单:

#include <iostream>
int main(int argc, char ** argv) {
    Foo foo { 1, 2, 3, 4 };

    for(auto & mem : foo) {
        std::cout << mem.get() << std::endl;
        mem.set(3);
    }

    for(auto & mem : foo) {
        std::cout << mem.get() << std::endl;
    }
}

可以在ideone

上找到POC