开发者

BOOST_FOREACH & templates without typedef

When I work with BOOST_FOREACH, there isn't a problem with simple templates 开发者_Python百科as vector. But when I try to iterate through map > for example I need to typedef the element type.

Is there any workaround?


There is a problem because it is a macro, and therefore cannot handle types containing commas (preprocessor doesn't know about templates).

You can also declare the variable before the loop, see documentation.

std::map<int, double> my_map;

//1)
typedef std::pair<int, double> MyPair;
BOOST_FOREACH(MyPair p, my_map) { ... }

//2)
std::pair<int, double> p;
BOOST_FOREACH(p, my_map) { ... }

Edit:

There is a further complication with std::map in particular: the value_type is not std::pair<Key, Value>, but std::pair<const Key, Value>.

Hence, if you go with the typedef, a more proper way (and the only way if you want to use a reference in the foreach loop) is to use

typedef std::pair<const int, double> MyPair;
//or
typedef std::map<int, double>::value_type MyPair;

BOOST_FOREACH(MyPair& ref, my_map) { ... }

However, that won't work if you want to use a variable declared before the loop, since you can't assign to a std::pair<const int, double> instance later (can't assign to the const field), in which case you can only use pair<int, double> as boost's manual shows.


If you need to iterate over a map, the easiest way is to use tuples, since getting the correct type in order to typedef, is troublesome. Here is how you can use tuples:

std::map<int, double> my_map;
int key;
double value;
BOOST_FOREACH(boost::tie(key, value), my_map) { ... }

Just a note, the commas will work here because parenthesis are placed around key and value. The preprocessor only understands commas and parenthesis(and c99 requires it to understand quotation marks also). So, it can't parse the <> in std::pair<int, double>. However, we can use parenthesis to help the preprocessor. For example, if we have a a function that returns a container that is called like this:

BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile

So, we can place parenthesis around an expression and it will help the preprocessor:

BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile

However, in the case of a map, we can't place parenthesis around the declaration(because its not an expression). So this won't work:

BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work

Because it will get transformed into something like this (std::pair<int, double> p) = *it, and that, of course, is incorrect C++. But using a tie will work:

BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work

We just need to declare key and value outside of the loop(as shown above). Plus, it can make the loop have more meaningful names. You can write key instead of p.first, and value instead of p.second.


BOOST_FOREACH_PAIR is another option that works well in our experience:

http://lists.boost.org/Archives/boost/2009/09/156345.php

http://lists.boost.org/Archives/boost/2009/09/156366.php


This can be as simple as this:

BOOST_FOREACH(auto& p, my_map) { ... }

Using the C++11 standard, auto is like var in C#, it will do

BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜