
Hi, Boosters. First, sorry for my bad English and the long post. I have been much inspired by Eric Niebler's FOREACH. It is very nice and useful. However, I think there are some drawbacks in his implementation. First, Eric's FOREACH should explicitly specify the value type of the range. It is still bothering me in some cases. For example, std::map or a range of ranges. Second, the reference type should be declared when a value is written into the range. It seems unclear. Then, I show yet another idea to implement FOREACH. My implementation can provide the following syntax. vector<int> v; ..... FOREACH(iter, v){ cout << *iter << endl; } The code above can be considered that `iter' is declared as an iterator. In this syntax, the first problem I picked up is clearly solved. Moreover, when writing a value into the range, the code whould be int i = 0; FOREACH(iter, v){ *iter = i++; } It seems very clear. The second problem is solved, too. This syntax would be reasonable and familiar to C++ programmers. Of cource, all the stuffs in the macro and operator* are calculated in compile-time, and compilers can optimize at the same level as an equivalent handwritten for-loop. On the other hand, there is a very serious limitation in my code. A number of FOREACH in each translation unit is limited. With the implementation in the attached file, the number is limited up to 100. This number can be easily increased, but increasing it burdens a compiler. In addition, member access operator (operator->) cannot be used. I use a subtle implementation of compile-time global counter to emulate auto/decltype, and subtly hides them in FOREACH macro and iterator syntax. Please see the attached code for more detail. The attached code has been tested on GCC3.4.2, MSVC7.1 and MSVC8.0 beta 2. All the implementations are compliant to the standard, I believe so at least. By the way, my idea contains auto/decltype emulation, so such a syntax as followings can be also provided by using my idea. AUTO_ANY(less, boost::lambda::_1 < boost::lambda::_2); sort(v1, v2, auto_cast(less)); // the type of the lambda functor is restored. Of course, this does not look so nice. I would like to ask boosters how useful, portable and interesting my idea is. Thanks in advance.

A. Azuma wrote:
Unfortunately, this technique is not standards compliant. The problem is in this code: template<int n> struct test_auto_range_count_injector { friend char (&test_auto_range_count(auto_range_count_tag<n>))[n]; }; #define FOREACH_AUTO_RANGE_COUNT() \ sizeof( \ ::foreach_detail::test_auto_range_count( \ ::foreach_detail::auto_range_end_of_count_tag() \ ) \ ) On a strictly standards compliant compiler, a friend function that is only declared inside a class is found using argument dependant lookup - the compiler knows to look inside the class because one of it's parameters is the class (or a descendant of it). Here there is no such parameter so the compiler doesn't know that it needs to look in test_auto_range_count_injector<n>. As far as I know the only compilers that work that way are EDG based compilers (eg. Intel, Comeau) in strict mode. This technique will work on EDG compilers if strict mode isn't on. The same applies to the friend funcions in auto_iterator<id, Iterator>. Daniel

2005/10/9, Daniel James <daniel@calamity.org.uk>:
Ah, I see. I overlooked this problem. I'm ashamed of my misinterpretation . After a little thought, I have concluded that there might not be any tricks to enable this kind of ADL. I would have to abandon my idea. Does anyone have good idea? Anyway, thank you for your comments.

A. Azuma wrote:
No reason to be ashamed -- it was a clever idea. There was one other person during the FOREACH review who argued for a similar interface, using TYPEOF in the implementation. There are a few reasons IMO why it wasn't a good idea: 1) It would have required people to register types with TYPEOF in order to use FOREACH. Unacceptable, IMO. (Your idea doesn't suffer from this, but it's non-standard.) 2) The current signature of FOREACH (FOREACH(type var, sequence)) mirrors the foreach construct of other popular languages. Also, this is the signature likely to be adopted should a new foreach looping construct be added to C++. 3) FOREACH(iter, sequence) doesn't make as strong a guarantee as does FOREACH(type var, sequence). With the second, you can be sure that every element in the sequence wiil be visited exactly once, and we won't walk off the end of the sequence. But with FOREACH(iter, sequence), nothing is stopping people from burying a ++iter somewhere in the loop body, throwing off the looping mechanism. When you need an iterator, there is always the general for(;;) statement. Use FOREACH for the simple, common cases. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
<snip> Oh, and I forgot ... 4) It breaks some perfectly reasonable assumptions. Consider: std::string str = "hello"; std::string::iterator iter = str.begin(); FOREACH(iter, str) { if(some-condition) break; } // use iter here People familiar with for(;;) would naturally expect this code to reuse the variable "iter" found in the enclosing scope, but with your version it wouldn't. Rather, it would create a new var named iter, hiding the outer one. The code after the loop would be using the outer iter, which is still pointing at the beginning of the string. Very counter-intuitive. -- Eric Niebler Boost Consulting www.boost-consulting.com
participants (3)
-
A. Azuma
-
Daniel James
-
Eric Niebler