我有一个这样的课程:
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类型)
答案 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