Ric*_*per 34 c++ foreach list c++11
我是C/C++编程的新手,但我已经用C#编程了1.5年了.我喜欢C#而且我喜欢List类,所以我想在C++中创建一个List类作为练习.
List<int> ls;
int whatever = 123;
ls.Add(1);
ls.Add(235445);
ls.Add(whatever);
Run Code Online (Sandbox Code Playgroud)
该实现类似于任何Array List类.我有一个T* vector存储项目的成员,当这个存储空间即将完全填满时,我会调整它的大小.
请注意,这不是用于生产,这只是一个练习.我很了解vector<T>和朋友们.
现在我想循环浏览列表中的项目.我不喜欢用for(int i=0;i<n; i==).我输入for了视觉工作室,等待Intellisense,它建议我:
for each (object var in collection_to_loop)
{
}
Run Code Online (Sandbox Code Playgroud)
这显然不适用于我的List实现.我想我可以做一些宏观魔术,但这感觉就像一个巨大的黑客.实际上,最让我烦恼的是传递类似的类型:
#define foreach(type, var, list)\
int _i_ = 0;\
##type var;\
for (_i_ = 0, var=list[_i_]; _i_<list.Length();_i_++,var=list[_i_])
foreach(int,i,ls){
doWork(i);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:有没有办法让这个自定义List类使用foreach-like循环?
Yuu*_*shi 45
首先,for-each循环的语法C++不同于C#(它也称为a range based for loop.它具有以下形式:
for(<type> <name> : <collection>) { ... }
Run Code Online (Sandbox Code Playgroud)
例如,使用a std::vector<int> vec,它将类似于:
for(int i : vec) { ... }
Run Code Online (Sandbox Code Playgroud)
在封面下,这有效地使用了返回迭代器的begin()和end()成员函数.因此,要允许自定义类使用for-each循环,您需要提供一个begin()和一个end()函数.这些通常是超载的,返回a iterator或a const_iterator.实现迭代器可能很棘手,虽然使用类似矢量的类并不太难.
template <typename T>
struct List
{
T* store;
std::size_t size;
typedef T* iterator;
typedef const T* const_iterator;
....
iterator begin() { return &store[0]; }
const_iterator begin() const { return &store[0]; }
iterator end() { return &store[size]; }
const_iterator end() const { return &store[size]; }
...
};
Run Code Online (Sandbox Code Playgroud)
通过这些实现,您可以使用如上所述的基于范围的循环.
mas*_*ilo 20
让我们iterable成为一个类型Iterable.然后,为了做
for (Type x : iterable)
Run Code Online (Sandbox Code Playgroud)
编译时,必须有被调用的类型Type,IType并且必须有函数
IType Iterable::begin()
IType Iterable::end()
Run Code Online (Sandbox Code Playgroud)
IType 必须提供功能
Type operator*()
void operator++()
bool operator!=(IType)
Run Code Online (Sandbox Code Playgroud)
整个结构是非常复杂的语法糖类
for (IType it = iterable.begin(); it != iterable.end(); ++it) {
Type x = *it;
...
}
Run Code Online (Sandbox Code Playgroud)
而不是Type,可以使用任何兼容类型(如const Type或Type&),这将具有预期的含义(constness,reference-instead-copy等).
由于整个扩展在语法上发生,您还可以稍微更改运算符的声明,例如,*它返回引用或者const IType& rhs根据需要使用!= a .
请注意,for (Type& x : iterable)如果*it不返回引用,则无法使用该表单(但如果它返回引用,则也可以使用副本版本).
另请注意,它operator++()定义了运算符的前缀版本++- 但是除非您明确定义后缀,否则它也将用作后缀运算符++.如果你只提供一个后缀++,那么ranged-for将无法编译,btw.can被声明为operator++(int)(dummy int参数).
最小的工作示例:
#include <stdio.h>
typedef int Type;
struct IType {
Type* p;
IType(Type* p) : p(p) {}
bool operator!=(IType rhs) {return p != rhs.p;}
Type& operator*() {return *p;}
void operator++() {++p;}
};
const int SIZE = 10;
struct Iterable {
Type data[SIZE];
IType begin() {return IType(data); }
IType end() {return IType(data + SIZE);}
};
Iterable iterable;
int main() {
int i = 0;
for (Type& x : iterable) {
x = i++;
}
for (Type x : iterable) {
printf("%d", x);
}
}
Run Code Online (Sandbox Code Playgroud)
产量
0123456789
Run Code Online (Sandbox Code Playgroud)
您可以使用以下宏伪造每个范围(例如,对于较旧的C++编译器):
#define ln(l, x) x##l // creates unique labels
#define l(x,y) ln(x,y)
#define for_each(T,x,iterable) for (bool _run = true;_run;_run = false) for (auto it = iterable.begin(); it != iterable.end(); ++it)\
if (1) {\
_run = true; goto l(__LINE__,body); l(__LINE__,cont): _run = true; continue; l(__LINE__,finish): break;\
} else\
while (1) \
if (1) {\
if (!_run) goto l(__LINE__,cont);/* we reach here if the block terminated normally/via continue */ \
goto l(__LINE__,finish);/* we reach here if the block terminated by break */\
} \
else\
l(__LINE__,body): for (T x = *it;_run;_run=false) /* block following the expanded macro */
int main() {
int i = 0;
for_each(Type&, x, iterable) {
i++;
if (i > 5) break;
x = i;
}
for_each(Type, x, iterable) {
printf("%d", x);
}
while (1);
}
Run Code Online (Sandbox Code Playgroud)
(如果您的编译器甚至没有auto,请使用declspec或传递IType).
输出:
1234500000
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,由于其复杂的结构continue,break它将与此一起工作.有关更多C-preprocessor hacking以创建自定义控件结构,请参阅http://www.chiark.greenend.org.uk/~sgtatham/mp/.
Intellisense建议的语法不是C++; 或者它是一些MSVC扩展.
C++ 11具有基于范围的for循环,用于迭代容器的元素.您需要为类实现begin()和end()成员函数,它们将迭代器返回到第一个元素,并分别返回最后一个元素.当然,这意味着您还需要为您的类实现合适的迭代器.如果你真的想走这条路,你可能想看看Boost.IteratorFacade ; 它减少了自己实现迭代器的痛苦.
之后你就可以这样写:
for( auto const& l : ls ) {
// do something with l
}
Run Code Online (Sandbox Code Playgroud)
此外,由于您是C++的新手,我想确保您知道标准库有多个容器类.
| 归档时间: |
|
| 查看次数: |
54700 次 |
| 最近记录: |