Qt'中foreach的实现

来源:互联网 发布:最新网络名词英文 编辑:程序博客网 时间:2024/04/27 21:49

foreach可以用来遍历容器,比如下面的使用场景:

QVector<int> container;container.push_back(1);container.push_back(2);container.push_back(3);foreach(int x, container){    qDebug() << x;}
关于foreach的实现代码可以在QtCore的qglobal.h中查看。本篇博客介绍下它的大概实现,可以当作是对它的模拟仿真。

上面提到了它的应用场景,也就是它的使用方法。看下它的原型:

 Q_FOREACH(variable, container)

variable表示容器中的每个元素,包括类型和变量。container表示容器对象。foreach本身就是一个宏定义,内容是对容器的遍历。遍历容器,可以使用for循环来做,比如:

for (int i = 0; i < container.size(); ++i){    int x = container[i];    qDebug() << x;}
或者,可以使用迭代器来实现,比如:
typedef QVector<int> Container;for (Container::const_iterator iter = container.begin(); iter != container.end(); ++iter){    int x = *iter;    qDebug() << x;}
使用迭代器方式,应该如何实现?

foreach传入container参数,container的类型不确定,还需要取得迭代器,取迭代器的begin()和end(),首先面临的问题是如何取得容器类型,容器的迭代器。

类型提取,类型萃取,可以使用模板。比如:

template<typename Container>typename Container::iterator begin(const Container& c){    //typedef Container::iterator Iterator;    return c.begin();}

可以取得模板类型的iter,begin,end,但是模板不能直接使用。可以考虑把这几个变量放在一个类中,比如:

template<typename Container>class DummyClass{public:    DummyClass(const Container& c) : _c(c), _b(c.begin()), _e(c.end()){}    const Container& _c;    typename Container::iterator _b, _e;};

DummyClass<QVector<int> > dummy(container);for (; dummy._b != dummy._e; ++dummy._b){...}
解决了迭代器变量的问题,下面面临的是如何使用它。使用模板类,需要传入模板类型。因此,还需要能够提取模板类型。

template<typename T>T getType(const T& t) { return T(0);}
使用模板推导功能来提取容器的类型,如下:

template<typename T>DummyClass<T> getNewContainer(const T& c) { return DummyClass<T>(c);}
这样就可以得到一个DummyClass<Container>类型的变量。
qDebug() << *getNewContainer(container)._b;

需要有一个DummyClass<T>类型的对象,使用这个对象去操作迭代器遍历。但是这个对象的T仍然需要指明。需要一个类型A,A的对象a,可以直接取使用DummyClass<T>类型的变量。现在的问题在于如何取声明中定义这个类型A。
解决方式是使用继承,给DummyClass增加一个父类,这个父类非模板类型。

class DummyBase {};template<typename Container>class DummyClass : public DummyBase{...};
这样,可以声明一个变量类型DummyBase container,然而它实际的内容是DummyClass<T>类型的派生类对象。
const DummyBase& _container = getNewContainer(container);
但是实际使用的时候仍然是派生类类型,需要再增加一个转换函数:
template<typename T>const DummyClass<T>* convertDummy(const DummyBase* base, const T*) {return static_cast<const DummyClass<T>* >(base);}
需要说明一下,const T*是为了推导模板使用的。
至此,模板的问题解决了。
下面就是使用for循环,DummyClass对象有了,就可以进行遍历了。
for (const DummyBase& _container = getNewContainer(container); convertDummy(&_container, &container)->_b != convertDummy(&_container, &container)->_e; ++convertDummy(&_container, &container)->_b)
等等,variable还没有使用呢,该如何使用呢?
双层循环,上面的一层循环迭代器已经有了,这一层只需要将它的值赋给variable就可以了,但是还面临的是,如何结束这层的循环呢?
Qt中的做法是在DummyClass中增加一个整数标志位,上层循环的时候给一个初始值0,下层循环判断是否是1,根据它结束下层循环,并重新设置整数标志位。
下面附上完整的仿真代码:
class DummyBase {};template<class Container>class DummyClass : public DummyBase{public:typedef typename Container::const_iterator iterator;DummyClass(const Container& c) : _c(c), _b(c.begin()), _e(c.end()), _k(0) {}//iterator begin(){ return _b;}//iterator end() { return _e; }bool condition() const { return ++_k && _b != _e;}public:const Container& _c;mutable iterator _b, _e;mutable int _k;};template<class T>DummyClass<T> getNewContainer(const T& c) { return DummyClass<T>(c);}template<class T>const DummyClass<T>* convertDummy(const DummyBase* base, const T*) {return static_cast<const DummyClass<T>* >(base);}#define __Foreach(var, container) \for (const DummyBase& _container = getNewContainer(container); \convertDummy(&_container, &container)->condition(); convertDummy(&_container, &container)->_b++) \for(var = *convertDummy(&_container, &container)->_b; convertDummy(&_container, &container)->_k ; \--convertDummy(&_container, &container)->_k) \关于它的使用:QVector<int> container;container.push_back(1);container.push_back(2);container.push_back(3);container.push_back(4);__Foreach(int x, container){qDebug() << x;}
关于细节实现,需要实际编码体验。
原创文章,转载请联系作者。

0 0