
The formal review of Eric Nibbler's FOREACH macro starts today, April 25, and will continue until Monday, May 1st. I will be serving as review manager. BOOST_FOREACH is a macro that makes it simple to iterate over STL containers, ranges, arrays and null-terminated strings. Its performance approaches that of the hand-coded equivalent loop. BOOST_FOREACH uses Boost.Range can be extended to iterating user-defined collections by extending Boost.Range. The library is available at: http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler foreach.zip Please note that the documentation is also available separately from the sources. It also can be viewed online at: http://boost-sandbox.sourceforge.net/libs/foreach The library is known to work (with different compliance levels) at least on the following compilers: * Visual C++ 7.1 * Visual C++ Whidbey Beta * Visual C++ 7.0 * Visual C++ 6.0 * gcc 3.3.3 * Intel for Windows 8.0 * Intel for Windows 7.0 * Comeau 4.3.3 When submitting reviews, please state explicitly whether or not you believe that the library should be accepted into Boost. For more information on the Boost formal review process, please see http://www.boost.org/more/formal_review_process.htm. Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote
The formal review of Eric Nibbler's FOREACH macro starts today, April 25, ... For more information on the Boost formal review process, please see http://www.boost.org/more/formal_review_process.htm.
And for more information about the current state of the Boost formal review schedule, pleese see http://boost.org/more/formal_review_schedule.html Please don't get me wrong. I am not complaining about the fact that FOREACH has been moved ahead of TYPEOF. I am aware that it was ahead in the first place. I just don't like the way I am learning about this. Quite a mess, IMHO. Regards, Arkadiy

Arkadiy Vertleyb wrote:
And for more information about the current state of the Boost formal review schedule, pleese see http://boost.org/more/formal_review_schedule.html
Please don't get me wrong. I am not complaining about the fact that FOREACH has been moved ahead of TYPEOF. I am aware that it was ahead in the first place. I just don't like the way I am learning about this.
Quite a mess, IMHO.
I agree. I don't mean to single anybody out, but IIUC this is the responsibility of the review wizard. Tom is letting questions go unanswered on the list and not involving the group in decisions about the review schedule. Tom, if you're listening, I humbly request a more hands-on approach with more active involvement from you. If you don't have the time, perhaps someone else does. This is too important to let slide. -- Eric Niebler Boost Consulting www.boost-consulting.com

Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
absolutely
What is your evaluation of the design?
outstanding
What is your evaluation of the implementation?
also outstanding
What is your evaluation of the documentation?
describe pitfalls, if any. actually, there is one pitfall: BOOST_FOREACH(pair<Key, Value> &p, some_map) does not work, since the preprocessor just can't get over that first comma
What is your evaluation of the potential usefulness of the library?
it is hugely useful. i use it all the time
Did you try to use the library? With what compiler? Did you have any problems?
yes. with vc 7. no problems
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
in-depth study
Are you knowledgeable about the problem domain?
yes regards, Michael Toksvig "Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d4j89a$cd7$1@sea.gmane.org...
The formal review of Eric Nibbler's FOREACH macro starts today, April 25, and will continue until Monday, May 1st. I will be serving as review manager.
BOOST_FOREACH is a macro that makes it simple to iterate over STL containers, ranges, arrays and null-terminated strings. Its performance approaches that of the hand-coded equivalent loop. BOOST_FOREACH uses Boost.Range can be extended to iterating user-defined collections by extending Boost.Range.
The library is available at:
http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler foreach.zip
Please note that the documentation is also available separately from the sources. It also can be viewed online at:
http://boost-sandbox.sourceforge.net/libs/foreach
The library is known to work (with different compliance levels) at least on the following compilers:
* Visual C++ 7.1 * Visual C++ Whidbey Beta * Visual C++ 7.0 * Visual C++ 6.0 * gcc 3.3.3 * Intel for Windows 8.0 * Intel for Windows 7.0 * Comeau 4.3.3
When submitting reviews, please state explicitly whether or not you believe that the library should be accepted into Boost.
For more information on the Boost formal review process, please see http://www.boost.org/more/formal_review_process.htm.
Gennadiy
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

michael toksvig schrieb:
What is your evaluation of the documentation?
describe pitfalls, if any. actually, there is one pitfall:
BOOST_FOREACH(pair<Key, Value> &p, some_map)
does not work, since the preprocessor just can't get over that first comma
this could be worked around with C99 variadic macros if available, something like: #define _BOOST_FOREACH2(a1,a2,...) BOOST_FOREACH2(a1,a2) #define _BOOST_FOREACH3(a1,a2,a3,...) BOOST_FOREACH3(a1,a2,a3) // ... #define _BOOST_FOREACH(a1,a2,a3,a4,a5,a6,a7,a8,a9,nr,...) _BOOST_FOREACH##nr(a1,a2,a3,a4,a5,a6,a7,a8,a9) #define BOOST_FOREACH(...) _BOOST_FOREACH(__VA_ARGS__,9,8,7,6,5,4,3,2,1) -- Stefan Strasser

Stefan Strasser wrote:
michael toksvig schrieb:
BOOST_FOREACH(pair<Key, Value> &p, some_map)
does not work, since the preprocessor just can't get over that first comma
this could be worked around with C99 variadic macros if available, something like:
#define _BOOST_FOREACH2(a1,a2,...) BOOST_FOREACH2(a1,a2) #define _BOOST_FOREACH3(a1,a2,a3,...) BOOST_FOREACH3(a1,a2,a3) // ...
#define _BOOST_FOREACH(a1,a2,a3,a4,a5,a6,a7,a8,a9,nr,...) _BOOST_FOREACH##nr(a1,a2,a3,a4,a5,a6,a7,a8,a9)
#define BOOST_FOREACH(...) _BOOST_FOREACH(__VA_ARGS__,9,8,7,6,5,4,3,2,1)
Clever, but there is an ambiguity here. What is the relations of the arguments in BOOST_FOREACH2(a1,a2,a3)? Do a1 and a2 together make up the loop variable declaration, or do a2 and a3 together form the collection expression: case 1: BOOST_FOREACH( std::pair<int,int> p, some_map ) case 2: BOOST_FOREACH( int i, some_trait<this,that>::some_list() ) I suppose you could say that case 2 can always be handled with a set of parens, as in: BOOST_FOREACH( int i, (some_trait<this,that>::some_list()) ) Therefore, all macro args but the last should be interpreted as part of the loop variable declaration. Anyway, I haven't heard of a major C++ compiler supporting C99 varargs. Is there one? I don't think we have a config macro for detecting it. Michael Toksvig's original point is a good one though. There should be a pitfalls section in the doc that warns people of this. I'll put it on my list of ToDo's. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler schrieb:
Stefan Strasser wrote:
michael toksvig schrieb:
BOOST_FOREACH(pair<Key, Value> &p, some_map)
does not work, since the preprocessor just can't get over that first comma
this could be worked around with C99 variadic macros if available, something like:
Clever, but there is an ambiguity here. What is the relations of the arguments in BOOST_FOREACH2(a1,a2,a3)? Do a1 and a2 together make up the loop variable declaration, or do a2 and a3 together form the collection expression:
case 1: BOOST_FOREACH( std::pair<int,int> p, some_map )
case 2: BOOST_FOREACH( int i, some_trait<this,that>::some_list() )
right, haven't thought of that. but I still think the workaround is convenient because - case 1 is more common than case 2 - both cases fail without workaround - the user can workaround case 2(parens), but can't case 1(at least, not easily, without typedef)
Anyway, I haven't heard of a major C++ compiler supporting C99 varargs. Is there one? I don't think we have a config macro for detecting it.
gcc and intel support it by default, como does with --c99 don't know about others, but 3 major ones are a good deal. -- Stefan Strasser

Stefan Strasser schrieb:
Eric Niebler schrieb:
Stefan Strasser wrote:
michael toksvig schrieb:
BOOST_FOREACH(pair<Key, Value> &p, some_map)
does not work, since the preprocessor just can't get over that first comma
this could be worked around with C99 variadic macros if available,
I've written two small patches to do this: http://www-user.uni-bremen.de/~strasser/config.patch against boost/config/compiler/ define BOOST_VARIADIC_MACROS if available works with gcc and intel cc the version numbers(3.3 for gcc, 7.0 for intel) are pessimistic guesses from tests and internet posts. http://www-user.uni-bremen.de/~strasser/foreach.patch against boost-sandbox/boost/foreach.hpp BOOST_FOREACH(VAR,COL) up to 10 commas inside VAR, none inside COL Regards, -- Stefan Strasser

Stefan Strasser schrieb:
Eric Niebler schrieb:
Stefan Strasser wrote:
michael toksvig schrieb:
BOOST_FOREACH(pair<Key, Value> &p, some_map)
does not work, since the preprocessor just can't get over that first comma
this could be worked around with C99 variadic macros if available,
I've written two small patches to do this:
http://www-user.uni-bremen.de/~strasser/config.patch against boost/config/compiler/
define BOOST_VARIADIC_MACROS if available works with gcc and intel cc
the version numbers(3.3 for gcc, 7.0 for intel) are pessimistic guesses from tests and internet posts.
http://www-user.uni-bremen.de/~strasser/foreach.patch against boost-sandbox/boost/foreach.hpp
BOOST_FOREACH(VAR,COL)
up to 10 commas inside VAR, none inside COL
Regards,
-- Stefan Strasser

Eric Niebler wrote:
Stefan Strasser wrote:
michael toksvig schrieb:
BOOST_FOREACH(pair<Key, Value> &p, some_map)
does not work, since the preprocessor just can't get over that first comma
this could be worked around with C99 variadic macros if available, something like:
Clever, but there is an ambiguity here. What is the relations of the arguments in BOOST_FOREACH2(a1,a2,a3)? Do a1 and a2 together make up the loop variable declaration, or do a2 and a3 together form the collection expression
Maybe you could use something like this: http://tinyurl.com/8s7ba Jonathan

"Eric Niebler" <eric@boost-consulting.com> wrote
I suppose you could say that case 2 can always be handled with a set of parens, as in:
BOOST_FOREACH( int i, (some_trait<this,that>::some_list()) )
Therefore, all macro args but the last should be interpreted as part of the loop variable declaration.
I have used the BOOST_FOREACH macro and its ok. As its main raison d'aitre is brevity, why do I need to explicitly provide the loop variable.I would hope for something like: FOREACH(my_container){ std::cout << *_ << '\n'; } IOW the boost::lambda placeholders could be used. Is not foreach a subset of the lambda functionality. (Proponents of lambda always cite this is an example.) I dont know of a reason to require conversions as in the example: short array_short[] = {1,2,3}; BOOST_FOREACH( int i, array_short ) { // The short was implicitly converted to an int } What is the point of the example? FWIW A naive method to do the above is as: #define FOR_EACH(cont) \ for (BOOST_TYPEOF( cont )>::iterator _ = cont ## .begin();\ _ != cont ## .end();\ ++ _ ) exept require *_ as opposed to _ However maybe this is an advantage... because the iterator is exposed then more loop information is avaialable eg if _ == my_container::begin() etc., which is an advantage over simply having the element available so making things more versatile. regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> wrote
FWIW A naive method to do the above is as:
#define FOR_EACH(cont) \ for (BOOST_TYPEOF( cont )>::iterator _ = cont ## .begin();\ _ != cont ## .end();\ ++ _ )
FWIW the following seems to do the job including for c-style strings and const containers. Is the BOOST_FOREACH complexity necessary? (Again I prefer the lambda style iterator, for versatlity ... ) #include <boost/typeof/typeof.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #define FOR_EACH(cont) \ for (BOOST_AUTO( _ , boost::begin(cont) );\ _ != boost::end(cont);\ ++ _ ) int main() { const char * test = "hello"; FOR_EACH(test){ if ( _ == boost::begin(test) ){ std::cout<< "["; } std::cout << *_; if( std::distance( _ , boost::end(test) ) > 1){ std::cout <<','; } else { std::cout << ']'; } } } Are there advantages to the BOOST_FOREACH approach? regards Andy Little

"Andy Little" <andy@servocomm.freeserve.co.uk> wrote
FWIW A naive method to do the above is as:
#define FOR_EACH(cont) \ for (BOOST_TYPEOF( cont )>::iterator _ = cont ## .begin();\ _ != cont ## .end();\ ++ _ )
FWIW the following seems to do the job including for c-style strings and const containers. Is the BOOST_FOREACH complexity necessary?
(Again I prefer the lambda style iterator, for versatlity ... )
#include <boost/typeof/typeof.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp>
#define FOR_EACH(cont) \ for (BOOST_AUTO( _ , boost::begin(cont) );\ _ != boost::end(cont);\ ++ _ )
int main() { const char * test = "hello"; FOR_EACH(test){ if ( _ == boost::begin(test) ){ std::cout<< "["; } std::cout << *_; if( std::distance( _ , boost::end(test) ) > 1){ std::cout <<','; } else { std::cout << ']'; } } }
Are there advantages to the BOOST_FOREACH approach?
It doesn't require type/template registration. Regards, Arkadiy

Andy Little wrote:
#define FOR_EACH(cont) \ for (BOOST_AUTO( _ , boost::begin(cont) );\ _ != boost::end(cont);\ ++ _ )
<snip>
Are there advantages to the BOOST_FOREACH approach?
Yes. BOOST_TYPEOF and BOOST_AUTO require types to be registered. BOOST_FOREACH does not. BOOST_AUTO is also a large dependency, and will induce large compile times unnecessarily. Also, your code doesn't work if "cont" is an unnamed temporary, and it will cause "cont" to be reevaluated multiple times. In short, the complexity of BOOST_FOREACH is needed to make it work as much like a keyword as possible. -- Eric Niebler Boost Consulting www.boost-consulting.com

Andy Little wrote:
I have used the BOOST_FOREACH macro and its ok. As its main raison d'aitre is brevity, why do I need to explicitly provide the loop variable.I would hope for something like:
FOREACH(my_container){ std::cout << *_ << '\n'; }
IOW the boost::lambda placeholders could be used.
What about nested invocations for BOOST_FOREACH: int a[100][200]; int sum = 0; BOOST_FOREACH(int (&x)[200], a) BOOST_FOREACH(int i, x) sum += i; ?
I dont know of a reason to require conversions as in the example: short array_short[] = {1,2,3}; BOOST_FOREACH( int i, array_short ) { // The short was implicitly converted to an int } What is the point of the example?
Conversions aren't "required", they are allowed. The point is to show that the loop variable doesn't have to have the same type as the element type, it only must be convertible.
FWIW A naive method to do the above is as:
#define FOR_EACH(cont) \ for (BOOST_TYPEOF( cont )>::iterator _ = cont ## .begin();\ _ != cont ## .end();\ ++ _ )
exept require *_ as opposed to _
However maybe this is an advantage... because the iterator is exposed then more loop information is avaialable eg if _ == my_container::begin() etc., which is an advantage over simply having the element available so making things more versatile.
It makes BOOST_FOREACH harder to extend. Not every sequence that users may want to iterate has anything like an iterator which is dereferencable. It is currently possible to make such non-STL sequences work with FOREACH with little effort, but after this change it would be impossible. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote
What about nested invocations for BOOST_FOREACH:
int a[100][200]; int sum = 0;
BOOST_FOREACH(int (&x)[200], a) BOOST_FOREACH(int i, x) sum += i;
?
Its a fair point but just as possible the other way: FOR_EACH(a){ BOOST_AUTO(& x, *_); // or int (&x)[200] = *_; FOR_EACH(x) sum += *_; }
I dont know of a reason to require conversions as in the example: short array_short[] = {1,2,3}; BOOST_FOREACH( int i, array_short ) { // The short was implicitly converted to an int } What is the point of the example?
Conversions aren't "required", they are allowed. The point is to show that the loop variable doesn't have to have the same type as the element type, it only must be convertible.
OK.
However maybe this is an advantage... because the iterator is exposed then more loop information is avaialable eg if _ == my_container::begin() etc., which is an advantage over simply having the element available so making things more versatile.
It makes BOOST_FOREACH harder to extend. Not every sequence that users may want to iterate has anything like an iterator which is dereferencable. It is currently possible to make such non-STL sequences work with FOREACH with little effort, but after this change it would be impossible.
Ok.. but the main use would be with standard containers I would guess. I cant argue about what users may require. I think that other collections (e.g boost::graph) work quite hard to try to be consistent with the std algorithms. Is there a motivating example in the documentation? regards Andy Little

Andy Little wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote
What about nested invocations for BOOST_FOREACH:
int a[100][200]; int sum = 0;
BOOST_FOREACH(int (&x)[200], a) BOOST_FOREACH(int i, x) sum += i;
?
Its a fair point but just as possible the other way:
FOR_EACH(a){ BOOST_AUTO(& x, *_); // or int (&x)[200] = *_; FOR_EACH(x) sum += *_; }
Andy, I think you are arguing for a design which is untenable. I would not accept a dependency on BOOST_AUTO, and I would not require users to register types and iterators with Boost.Typeof in order to use BOOST_FOREACH. You're trying to make BOOST_FOREACH easier to use, and I appreciate that, but an anology about babies and bathwater seems appropriate here. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote
Andy, I think you are arguing for a design which is untenable. I would not accept a dependency on BOOST_AUTO, and I would not require users to register types and iterators with Boost.Typeof in order to use BOOST_FOREACH. You're trying to make BOOST_FOREACH easier to use, and I appreciate that, but an anology about babies and bathwater seems appropriate here.
Ok I'll leave it at that :-) regards Andy Little

Gennadiy Rozental <gennadiy.rozental <at> thomson.com> writes:
The library is known to work (with different compliance levels) at least on the following compilers:
* Visual C++ 7.1 * Visual C++ Whidbey Beta * Visual C++ 7.0
VC70 sometimes generates the wrong code (wrong stack offset for local variables) causing stack corruption when using FOREACH macro. Has happened to me several times. I have not been able to isolate the problem but it seem to only happen in large functions with many local variables.

What is your evaluation of the design?
Very good. The API is nice and clean. I like the flexibility it gives to the user (either lvalues or rvalues, either declare a variable or just use it, etc.), so that he does not have to "think" much. I also like that you can cleanly use break in the middle of the loop. I also evaluated competing implementation (including Qt 4's foreach) and I believe that Eric's is by far the best.
What is your evaluation of the implementation?
State of the art. I did not try to understand really everything, but I followed most of the code, and I also read Eric's article about the so-called "?: metaprogramming", and it's really clever stuff.
What is your evaluation of the documentation?
Cute and simple. Others mentioned that a warning should be added about the use of commas in template argument lists.
What is your evaluation of the potential usefulness of the library?
Did you try to use the library? With what compiler? Did you have any
It is really useful. We are already using it in many applications, and enginereers just love it. problems? VC71, no problems whatsoever.
How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
In-depth study.
Are you knowledgeable about the problem domain?
Yes, I also work with other languages which provide foreach-like language support, so I know what we are heading for here. I believe the library should be accepted into Boost. Giovanni Bajo

"Gennadiy Rozental" wrote:
The formal review of Eric Nibbler's FOREACH macro starts
http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler foreach.zip
I use FOREACH and like it. It should be part of Boost. The only time when I needed to fall back on old for(;;) was when I wanted to know whether I am within first/last loop cycle, like in: for (int i = 0; i < n; ++i) { if (i == 0) cout << "["; ... if (i + 1 == n) cout << "]"; } The documentation should have example for std::set and std::map. Example for multi-index container would be much useful. Example for stepping though vector<vector<int> > in two loops as well. I tried to run the test under Intel 7.0, VC6.5 and BCB 6.4. Notes from the fight are bellow. (I managed to get Intel 7 working. Slightly modified regress.cpp is included.) /Pavel --------------------------------------------------------- Trying to compile the test with Intel C++ 7.0 plugged in VC6 IDE wth old Dinkumware I get error with line: std::list<int> my_list(int_iterator(1),int_iterator(6)); C:\work\reviews\foreach\libs\foreach\test\regress.cpp(29): error: no instance of constructor "std::list<_Ty, _A>::list [with _Ty=int, _A=std::allocator<int>]" matches the argument list argument types are: (int_iterator, int_iterator) std::list<int> my_list(int_iterator(1),int_iterator(6)); ^ This is because old Dinkumware doesn't support template members. This can be solved by using: #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) // Old Dinkumware doesn't support template members. // Lets fill the list with six ints of value 99. std::list<int> my_list(6, 99); #else std::list<int> my_list(int_iterator(1),int_iterator(6)); #endif in regress.cpp. --------------- Then I get second error: C:\work\reviews\boost-05-02-24-1300\boost/range/iterator.hpp(37): error: class "mine::dummy" has no member "iterator" typedef BOOST_DEDUCED_TYPENAME C::iterator type; ^ detected during instantiation of class "boost::range_iterator<C> [with C=const mine::dummy]" at line 64 of "C:\work\reviews\foreach\libs\foreach\test\regress.cpp" compilation aborted for C:\work\reviews\foreach\libs\foreach\test\regress.cpp (code 2) that looks as mistake in test (range<> really expects a richer "dummy" type). I "fixed" it by changing: struct dummy { typedef void iterator; }; Then the test works (Intel + old Dinkumware ) for both Debug and Release mode. ---------- With VC6 I get error: c:\work\reviews\foreach\libs\foreach\test\regress.cpp(58) : warning C4099: 'range_iterator<struct mine::dummy>' : type name first seen using 'class' now seen using 'struct' c:\work\reviews\foreach\libs\foreach\test\regress.cpp(63) : warning C4099: 'range_const_iterator<struct mine::dummy>' : type name first seen using 'class' now seen using 'struct' c:\work\reviews\foreach\libs\foreach\test\regress.cpp(66) : fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1794) I changed the struct range_const_iterator<mine::dummy> into class range_const_iterator<mine::dummy> but the ICE remained. I added #ifdef for VC6 to avoid the extending and then I got errors: C:\work\reviews\foreach\libs\foreach\test\regress.cpp(102) : error C2079: 'i' uses undefined class 'please_invoke_BOOST_TT_BROKEN_COMPILER_SPEC_on_cv_unqualified_pointee<int (*)[5]>' C:\work\reviews\foreach\libs\foreach\test\regress.cpp(146) : see reference to function template instantiation 'class std::vector<int,class std::allocator<int> > __cdecl to_vector_foreach_byval(int (&)[5])' being compiled C:\work\reviews\foreach\libs\foreach\test\regress.cpp(102) : error C2440: 'initializing' : cannot convert from 'class boost::detail::please_invoke_BOOST_TT_BROKEN_COMPILER_SPEC_on_cv_unqualified_pointee<int (*)[5]>' to 'int' Source or target has incomplete type C:\work\reviews\foreach\libs\foreach\test\regress.cpp(146) : see reference to function template instantiation 'class std::vector<int,class std::allocator<int> > __cdecl to_vector_foreach_byval(int (&)[5])' being compiled C:\work\reviews\foreach\libs\foreach\test\regress.cpp(88) : error C2664: 'push_back' : cannot convert parameter 1 from 'int [5]' to 'const int &' Reason: cannot convert from 'int [5]' to 'const int' This conversion requires a reinterpret_cast, a C-style cast or function-style cast C:\work\reviews\foreach\libs\foreach\test\regress.cpp(146) : see reference to function template instantiation 'class std::vector<int,class std::allocator<int> > __cdecl to_vector_for(int (&)[5])' being compiled C:\work\reviews\foreach\libs\foreach\test\regress.cpp(102) : error C2079: 'i' uses undefined class 'please_invoke_BOOST_TT_BROKEN_COMPILER_SPEC_on_cv_unqualified_pointee<int const (*)[5]>' C:\work\reviews\foreach\libs\foreach\test\regress.cpp(152) : see reference to function template instantiation 'class std::vector<int,class std::allocator<int> > __cdecl to_vector_foreach_byval(const int (&)[5])' being compiled .... I gave up at this point. I am attching regress.cpp with my fixes. ---------- When trying BCB 6.4 I got strange error in boost/addressof.hpp: [C++ Error] addressof.hpp(33): E2031 Cannot cast from 'int *' to 'const volatile char &' Full parser context regress.cpp(192): decision to instantiate: int ( *)[5] boost::int ( *)[5] addressof<int[5]>(int ( &)[5]) --- Resetting parser context for instantiation... regress.cpp(13): #include C:\work\reviews\boost-05-02-24-1300\boost/test/minimal.hpp minimal.hpp(38): #include C:\work\reviews\boost-05-02-24-1300\boost/test/utils/class_properties.hpp class_properties.hpp(29): #include C:\work\reviews\boost-05-02-24-1300\boost/utility/addressof.hpp addressof.hpp(20): namespace boost addressof.hpp(31): parsing: int ( *)[5] boost::int ( *)[5] addressof<int[5]>(int ( &)[5]) [C++ Error] addressof.hpp(33): E2031 Cannot cast from 'const int *' to 'const volatile char &' Full parser context regress.cpp(192): decision to instantiate: int ( *) const[5] boost::int ( *) const[5] addressof<int const[5]>(int ( &) const[5]) --- Resetting parser context for instantiation... regress.cpp(13): #include C:\work\reviews\boost-05-02-24-1300\boost/test/minimal.hpp minimal.hpp(38): #include C:\work\reviews\boost-05-02-24-1300\boost/test/utils/class_properties.hpp class_properties.hpp(29): #include C:\work\reviews\boost-05-02-24-1300\boost/utility/addressof.hpp addressof.hpp(20): namespace boost addressof.hpp(31): parsing: int ( *) const[5] boost::int ( *) const[5] addressof<int const[5]>(int ( &) const[5]) I may try to look deeper into it. ---------- EOF begin 666 regress.cpp M+R\@("A#*2!#;W!Y<FEG:'0@17)I8R!.:65B;&5R(#(P,#0N#0HO+R @57-E M+"!M;V1I9FEC871I;VX@86YD(&1I<W1R:6)U=&EO;B!A<F4@<W5B:F5C="!T M;R!T:&4-"B\O("!";V]S="!3;V9T=V%R92!,:6-E;G-E+"!697)S:6]N(#$N M,"X@*%-E92!A8V-O;7!A;GEI;F<@9FEL90T*+R\@($Q)0T5.4T5?,5\P+G1X M="!O<B!C;W!Y(&%T(&AT=' Z+R]W=W<N8F]O<W0N;W)G+TQ)0T5.4T5?,5\P M+G1X="D-"@T*+RH-"B!2979I<VEO;B!H:7-T;W)Y.@T*(" @,3,@1&5C96UB M97(@,C P-" Z($EN:71I86P@=F5R<VEO;BX-"BHO#0H-"B-I;F-L=61E(#QL M:7-T/@T*(VEN8VQU9&4@/'9E8W1O<CX-"B-I;F-L=61E(#QB;V]S="]T97-T M+VUI;FEM86PN:'!P/@T*(VEN8VQU9&4@/&)O;W-T+VET97)A=&]R+VET97)A M=&]R7W1R86ET<RYH<' ^#0HC:6YC;'5D92 \8F]O<W0O:71E<F%T;W(O8V]U M;G1I;F=?:71E<F%T;W(N:'!P/@T*(VEN8VQU9&4@(BXN+RXN+RXN+V)O;W-T M+V9O<F5A8V@N:'!P(@T*#0HO+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O#0HO+R!I;G1?:71E<F%T;W(-"B\O#0IT>7!E9&5F(&)O;W-T.CIC M;W5N=&EN9U]I=&5R871O<CQI;G0^(&EN=%]I=&5R871O<CL-"@T*+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+PT*+R\@9&5F:6YE(&-O;64@ M8V]N=&%I;F5R<PT*+R\-"F-H87(@;7E?;G1C<U]B=69F97);72 ](")<,5PR M7#-<-%PU(CL-"F-H87(@*FUY7VYT8W,@(#T@;7E?;G1C<U]B=69F97([#0II M;G0@;7E?87)R87E;72 ]('L@,2PR+#,L-"PU('T[#0HC:68@0D]/4U1?5T]2 M2T%23U5.1"A"3T]35%]$24Y+54U705)%7U-41$Q)0BP@/3T@,2D-"B\O($]L M9"!$:6YK=6UW87)E(&1O97-N)W0@<W5P<&]R="!T96UP;&%T92!M96UB97)S M+B -"B\O($QE=',@9FEL;"!T:&4@;&ES="!W:71H('-I>"!I;G1S(&]F('9A M;'5E(#DY+@T*<W1D.CIL:7-T/&EN=#X@;7E?;&ES="@V+" Y.2D[#0HC96QS M90T*<W1D.CIL:7-T/&EN=#X@;7E?;&ES="AI;G1?:71E<F%T;W(H,2DL:6YT M7VET97)A=&]R*#8I*3L-"B-E;F1I9@T*<W1D.CIP86ER/&EN=%]I=&5R871O M<BQI;G1?:71E<F%T;W(^(&UY7W!A:7(H:6YT7VET97)A=&]R*#$I+&EN=%]I M=&5R871O<B@V*2D[#0H-"FEN="!C;VYS=" H)FUY7V-O;G-T7V%R<F%Y*5LU M72 ](&UY7V%R<F%Y.PT*8VAA<B!C;VYS=" J;7E?8V]N<W1?;G1C<R @/2!M M>5]N=&-S.PT*<W1D.CIL:7-T/&EN=#X@8V]N<W0@)FUY7V-O;G-T7VQI<W0@ M/2!M>5]L:7-T.PT*<W1D.CIP86ER/&EN=%]I=&5R871O<BQI;G1?:71E<F%T M;W(^(&-O;G-T("9M>5]C;VYS=%]P86ER(#T@;7E?<&%I<CL-"@T*+R\@5D,V M('=I;&P@9F%I;"!H97)E('=I=&@@24-%#0HC:68@0D]/4U1?5T]22T%23U5. M1"A"3T]35%]-4U9#+" ^(#$R,# I#0HO+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O#0HO+R!D969I;F4@82!U<V5R+61E9FEN960@8V]L;&5C M=&EO;B!T>7!E(&%N9"!T96%C:"!"3T]35%]&3U)%04-((&AO=R!T;R!E;G5M M97)A=&4@:70-"B\O#0IN86UE<W!A8V4@;6EN90T*>PT*(" @('-T<G5C="!D M=6UM>2 -"B @("![#0H@(" @(" @('1Y<&5D968@=F]I9"!I=&5R871O<CL- M"B @("!].PT*?0T*#0IN86UE<W!A8V4@8F]O<W0-"GL-"B @("!T96UP;&%T M93P^#0H@(" @8VQA<W,@<F%N9V5?:71E<F%T;W(\;6EN93HZ9'5M;7D^#0H@ M(" @>PT*(" @('!U8FQI8SH-"B @(" @(" @='EP961E9B!C:&%R("H@='EP M93L-"B @("!].PT*(" @('1E;7!L871E/#X-"B @("!C;&%S<R!R86YG95]C M;VYS=%]I=&5R871O<CQM:6YE.CID=6UM>3X-"B @("![#0H@(" @<'5B;&EC M.@T*(" @(" @("!T>7!E9&5F(&-H87(@8V]N<W0@*B!T>7!E.PT*(" @('T[ M#0H@(" @8VAA<B J(&)E9VEN*&UI;F4Z.F1U;6UY)BD@>W)E='5R;B P.WT- M"B @("!C:&%R(&-O;G-T("H@8F5G:6XH;6EN93HZ9'5M;7D@8V]N<W0F*2![ M<F5T=7)N(# [?0T*(" @(&-H87(@*B!E;F0H;6EN93HZ9'5M;7DF*2![<F5T M=7)N(# [?0T*(" @(&-H87(@8V]N<W0@*B!E;F0H;6EN93HZ9'5M;7D@8V]N M<W0F*2![<F5T=7)N(# [?0T*?0T*(V5N9&EF("\O(%9#-B!W;W)K87)O=6YD M#0H-"B\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\-"B\O('1O M7W9E8W1O<E]F;W(-"B\O#0IT96UP;&%T93QT>7!E;F%M92!286YG93X-"G-T M9#HZ=F5C=&]R/&EN=#X@=&]?=F5C=&]R7V9O<B@@4F%N9V4@)B!R;F<@*0T* M>PT*(" @('-T9#HZ=F5C=&]R/&EN=#X@=F5C=#L-"B @("!T>7!E9&5F($)/ M3U-47T1%1%5#141?5%E014Y!344@8F]O<W0Z.G)A;F=E7W)E<W5L=%]I=&5R M871O<CQ286YG93XZ.G1Y<&4@:71E<F%T;W([#0H@(" @9F]R*&ET97)A=&]R M(&)E9VEN(#T@8F]O<W0Z.F)E9VEN*')N9RDL(&5N9" ](&)O;W-T.CIE;F0H M<FYG*3L-"B @(" @(" @8F5G:6X@(3T@96YD.R K*V)E9VEN*0T*(" @('L- M"B @(" @(" @=F5C="YP=7-H7V)A8VLH*F)E9VEN*3L-"B @("!]#0H@(" @ M<F5T=7)N('9E8W0[#0I]#0H-"B\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\-"B\O('1O7W9E8W1O<E]F;W)E86-H7V)Y=F%L#0HO+PT*=&5M M<&QA=&4\='EP96YA;64@4F%N9V4^#0IS=&0Z.G9E8W1O<CQI;G0^('1O7W9E M8W1O<E]F;W)E86-H7V)Y=F%L*"!286YG92 F(')N9R I#0I[#0H@(" @<W1D M.CIV96-T;W(\:6YT/B!V96-T.PT*(" @('1Y<&5D968@0D]/4U1?1$5$54-% M1%]465!%3D%-12!B;V]S=#HZ<F%N9V5?<F5S=6QT7VET97)A=&]R/%)A;F=E M/CHZ='EP92!I=&5R871O<CL-"B @("!T>7!E9&5F($)/3U-47T1%1%5#141? M5%E014Y!344@8F]O<W0Z.FET97)A=&]R7W9A;'5E/&ET97)A=&]R/CHZ='EP M92!V86QU93L-"B @("!"3T]35%]&3U)%04-(*"!V86QU92!I+"!R;F<@*0T* M(" @('L-"B @(" @(" @=F5C="YP=7-H7V)A8VLH:2D[#0H@(" @?0T*(" @ M(')E='5R;B!V96-T.PT*?0T*#0HO+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O#0HO+R!T;U]V96-T;W)?9F]R96%C:%]B>7)E9@T*+R\-"G1E M;7!L871E/'1Y<&5N86UE(%)A;F=E/@T*<W1D.CIV96-T;W(\:6YT/B!T;U]V M96-T;W)?9F]R96%C:%]B>7)E9B@@4F%N9V4@)B!R;F<@*0T*>PT*(" @('-T M9#HZ=F5C=&]R/&EN=#X@=F5C=#L-"B @("!T>7!E9&5F($)/3U-47T1%1%5# M141?5%E014Y!344@8F]O<W0Z.G)A;F=E7W)E<W5L=%]I=&5R871O<CQ286YG M93XZ.G1Y<&4@:71E<F%T;W([#0H@(" @='EP961E9B!"3T]35%]$14150T5$ M7U194$5.04U%(&)O;W-T.CII=&5R871O<E]R969E<F5N8V4\:71E<F%T;W(^ M.CIT>7!E(')E9F5R96YC93L-"B @("!"3T]35%]&3U)%04-(*"!R969E<F5N M8V4@:2P@<FYG("D-"B @("![#0H@(" @(" @('9E8W0N<'5S:%]B86-K*&DI M.PT*(" @('T-"B @("!R971U<FX@=F5C=#L-"GT-"@T*+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+PT*+R\@;75T871E7V9O<F5A8VA?8GER M968-"B\O#0IT96UP;&%T93QT>7!E;F%M92!286YG93X-"G9O:60@;75T871E M7V9O<F5A8VA?8GER968H(%)A;F=E("8@<FYG("D-"GL-"B @("!T>7!E9&5F M($)/3U-47T1%1%5#141?5%E014Y!344@8F]O<W0Z.G)A;F=E7W)E<W5L=%]I M=&5R871O<CQ286YG93XZ.G1Y<&4@:71E<F%T;W([#0H@(" @='EP961E9B!" M3T]35%]$14150T5$7U194$5.04U%(&)O;W-T.CII=&5R871O<E]R969E<F5N M8V4\:71E<F%T;W(^.CIT>7!E(')E9F5R96YC93L-"B @("!"3T]35%]&3U)% M04-(*"!R969E<F5N8V4@:2P@<FYG("D-"B @("![#0H@(" @(" @("LK:3L- M"B @("!]#0I]#0H-"@T*+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O+R\O M+R\O+PT*+R\@=&5S=%]M86EN#0HO+R @( T*:6YT('1E<W1?;6%I;B@@:6YT M+"!C:&%R*EM=("D-"GL-"B @(" O+R!N;VXM8V]N<W0@8V]N=&%I;F5R<R!B M>2!V86QU90T*(" @($)/3U-47T-(14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y M=F%L*&UY7V%R<F%Y*2 ]/2!T;U]V96-T;W)?9F]R*&UY7V%R<F%Y*2D[#0H@ M(" @0D]/4U1?0TA%0TLH=&]?=F5C=&]R7V9O<F5A8VA?8GEV86PH;7E?;G1C M<RD@(#T]('1O7W9E8W1O<E]F;W(H;7E?;G1C<RDI.PT*(" @($)/3U-47T-( M14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y=F%L*&UY7VQI<W0I(" ]/2!T;U]V M96-T;W)?9F]R*&UY7VQI<W0I*3L-"B @("!"3T]35%]#2$5#2RAT;U]V96-T M;W)?9F]R96%C:%]B>79A;"AM>5]P86ER*2 @/3T@=&]?=F5C=&]R7V9O<BAM M>5]P86ER*2D[#0H-"B @(" O+R!C;VYS="!C;VYT86EN97)S(&)Y('9A;'5E M#0H@(" @0D]/4U1?0TA%0TLH=&]?=F5C=&]R7V9O<F5A8VA?8GEV86PH;7E? M8V]N<W1?87)R87DI(#T]('1O7W9E8W1O<E]F;W(H;7E?8V]N<W1?87)R87DI M*3L-"B @("!"3T]35%]#2$5#2RAT;U]V96-T;W)?9F]R96%C:%]B>79A;"AM M>5]C;VYS=%]N=&-S*2 @/3T@=&]?=F5C=&]R7V9O<BAM>5]C;VYS=%]N=&-S M*2D[#0H@(" @0D]/4U1?0TA%0TLH=&]?=F5C=&]R7V9O<F5A8VA?8GEV86PH M;7E?8V]N<W1?;&ES="D@(#T]('1O7W9E8W1O<E]F;W(H;7E?8V]N<W1?;&ES M="DI.PT*(" @($)/3U-47T-(14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y=F%L M*&UY7V-O;G-T7W!A:7(I(" ]/2!T;U]V96-T;W)?9F]R*&UY7V-O;G-T7W!A M:7(I*3L-"@T*(" @("\O(&YO;BUC;VYS="!C;VYT86EN97)S(&)Y(')E9F5R M96YC90T*(" @($)/3U-47T-(14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y<F5F M*&UY7V%R<F%Y*2 ]/2!T;U]V96-T;W)?9F]R*&UY7V%R<F%Y*2D[#0H@(" @ M0D]/4U1?0TA%0TLH=&]?=F5C=&]R7V9O<F5A8VA?8GER968H;7E?;G1C<RD@ M(#T]('1O7W9E8W1O<E]F;W(H;7E?;G1C<RDI.PT*(" @($)/3U-47T-(14-+ M*'1O7W9E8W1O<E]F;W)E86-H7V)Y<F5F*&UY7VQI<W0I(" ]/2!T;U]V96-T M;W)?9F]R*&UY7VQI<W0I*3L-"B @("!"3T]35%]#2$5#2RAT;U]V96-T;W)? M9F]R96%C:%]B>7)E9BAM>5]P86ER*2 @/3T@=&]?=F5C=&]R7V9O<BAM>5]P M86ER*2D[#0H-"B @(" O+R!C;VYS="!C;VYT86EN97)S(&)Y(')E9F5R96YC M90T*(" @($)/3U-47T-(14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y<F5F*&UY M7V-O;G-T7V%R<F%Y*2 ]/2!T;U]V96-T;W)?9F]R*&UY7V-O;G-T7V%R<F%Y M*2D[#0H@(" @0D]/4U1?0TA%0TLH=&]?=F5C=&]R7V9O<F5A8VA?8GER968H M;7E?8V]N<W1?;G1C<RD@(#T]('1O7W9E8W1O<E]F;W(H;7E?8V]N<W1?;G1C M<RDI.PT*(" @($)/3U-47T-(14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y<F5F M*&UY7V-O;G-T7VQI<W0I(" ]/2!T;U]V96-T;W)?9F]R*&UY7V-O;G-T7VQI M<W0I*3L-"B @("!"3T]35%]#2$5#2RAT;U]V96-T;W)?9F]R96%C:%]B>7)E M9BAM>5]C;VYS=%]P86ER*2 @/3T@=&]?=F5C=&]R7V9O<BAM>5]C;VYS=%]P M86ER*2D[#0H-"B @(" O+R!M=71A=&4@=&AE(&UU=&%B;&4@8V]L;&5C=&EO M;G,-"B @("!M=71A=&5?9F]R96%C:%]B>7)E9BAM>5]A<G)A>2D[#0H@(" @ M;75T871E7V9O<F5A8VA?8GER968H;7E?;G1C<RD[#0H@(" @;75T871E7V9O M<F5A8VA?8GER968H;7E?;&ES="D[#0H-"B @(" O+R!C;VUP87)E('1H92!M M=71A=&5D(&-O;&QE8W1I;VYS('1O('1H92!A8W1U86P@<F5S=6QT<PT*(" @ M('-T9#HZ<&%I<CQI;G1?:71E<F%T;W(L:6YT7VET97)A=&]R/B!R97-U;'1S M*&EN=%]I=&5R871O<B@R*2QI;G1?:71E<F%T;W(H-RDI.PT*(" @($)/3U-4 M7T-(14-+*'1O7W9E8W1O<E]F;W)E86-H7V)Y=F%L*&UY7V%R<F%Y*2 ]/2!T M;U]V96-T;W)?9F]R*')E<W5L=',I*3L-"B @("!"3T]35%]#2$5#2RAT;U]V M96-T;W)?9F]R96%C:%]B>79A;"AM>5]N=&-S*2 @/3T@=&]?=F5C=&]R7V9O M<BAR97-U;'1S*2D[#0H@(" @0D]/4U1?0TA%0TLH=&]?=F5C=&]R7V9O<F5A M8VA?8GEV86PH;7E?;&ES="D@(#T]('1O7W9E8W1O<E]F;W(H<F5S=6QT<RDI M.PT*#0HC:68@0D]/4U1?5T]22T%23U5.1"A"3T]35%]-4U9#+" ^(#$R,# I M#0H@(" @+R\@;&]O<"!O=F5R(&$@=7-E<BUD969I;F5D('1Y<&4@*&IU<W0@ M;6%K92!S=7)E('1H:7,@8V]M<&EL97,I#0H@(" @;6EN93HZ9'5M;7D@9#L- M"B @("!"3T]35%]&3U)%04-(*"!C:&%R(&,L(&0@*0T*(" @('L-"B @(" @ M(" @*"AV;VED*6,I.R O+R!N;RUO< T*(" @('T-"B-E;F1I9@T*#0H@(" @ .<F5T=7)N(# [#0I]#0H` ` end

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message news:d4lq0a$is1$1@sea.gmane.org...
"Gennadiy Rozental" wrote:
The formal review of Eric Nibbler's FOREACH macro starts
http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler foreach.zip
I use FOREACH and like it. It should be part of Boost.
The only time when I needed to fall back on old for(;;) was when I wanted to know whether I am within first/last loop cycle, like in:
for (int i = 0; i < n; ++i) { if (i == 0) cout << "["; ... if (i + 1 == n) cout << "]"; }
Yeah. From time to time (but quite consistently) I also need first/last variable inside loop. You could use FOREACH with first: bool first = true; BOOST_FOREACH(... ) { if( first ) { .... first = false; } } I guess macro could provide this automatically, but I am not sure this convenience warrant an overhead for those who do not need it. Gennadiy

Pavel Vozenilek wrote:
Then I get second error:
C:\work\reviews\boost-05-02-24-1300\boost/range/iterator.hpp(37): error: class "mine::dummy" has no member "iterator" typedef BOOST_DEDUCED_TYPENAME C::iterator type; ^ detected during instantiation of class "boost::range_iterator<C> [with C=const mine::dummy]" at line 64 of
"C:\work\reviews\foreach\libs\foreach\test\regress.cpp" compilation aborted for C:\work\reviews\foreach\libs\foreach\test\regress.cpp (code 2)
that looks as mistake in test (range<> really expects a richer "dummy" type).
I "fixed" it by changing:
struct dummy { typedef void iterator; };
This is not a bug in the test. It is a compiler bug. range_iterator has been specialized for mine::dummy, but the compiler is not picking up the specialization. This test should be broken out and marked as an expected failure for this compiler. -- Eric Niebler Boost Consulting www.boost-consulting.com

Pavel Vozenilek wrote:
When trying BCB 6.4 I got strange error in boost/addressof.hpp:
I believe addressof has been patched in CVS for this problem with bcc32 5.6.4. I've run tests for Eric on FOREACH and I think the only problem we ran in to that couldn't be solved for bcc32 was you couldn't use an un-named temporary (i.e. result of function) as the range to iterate over. Cheers Russell

Minor point: the documentation should have link to the article on Artima.com. Minor point II: the #if (defined_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif could be added. /Pavel

I have been using the BOOST_FOREACH macro for quite some time and haven't had any problems with it at all. I would love to see it as part of boost. Thanks! David Brownell

Do you think the library should be accepted as a Boost library?
Yes
Did you try to use the library? With what compiler? Did you have any problems?
icc 8.1 linux gcc 3.3 linux gcc 3.4 linux gcc 4.0 20050418 linux no problems
What is your evaluation of the documentation?
I agree that it shouldn't be named "foreach", although it is very much keyword-like, but I think a "#define foreach BOOST_FOREACH" in the documentation examples would encourage its use. I'd like to see a few notes about possible performance impact of BOOST_FOREACH because of confused optimizers etc. in the documentation. there's almost none but you have to find out yourself if it's not documented. (I did so with icc and gcc. innerloops looked the same or almost the same. gcc generates some overhead outside the loop: a non-inlined call to addressof and 12 bytes of additional reserved stack space, which can be problematic with deep recursion)
What is your evaluation of the potential usefulness of the library?
very convenient, will use it
Are you knowledgeable about the problem domain?
user-perspective -- Stefan Strasser

Yes I think BOOST_FOREACH should definitely be accepted. * What is your evaluation of the design? Very easy to learn and use * What is your evaluation of the implementation? Can't comment * What is your evaluation of the documentation? Very good. Straight to the point and shows you how to use library * What is your evaluation of the potential usefulness of the library? Very useful. There are some loops I've written recently that require to know where we are in the container so will still have to use iterators for that, but in all other cases, I much prefer to use BOOST_FOREACH The only (slight) problem I can see over using iterators is that if you forget to declare the loop variable as a reference, then changing the value won't have any effect. iterators don't have this problem. * Did you try to use the library? With what compiler? Did you have any problems? Borland' bcc32 5.6.4. It can't handle r-values so I guess it has compliance level 2, but I'd like to see it added to the portability page all the same. * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? I've been using BOOST_FOREACH for a couple of months now. * Are you knowledgeable about the problem domain? Only as a user. Cheers Russell

Hi, I really don't like macros. I have a hard time accepting boost PP but at least we have never before used macros in a way that means that they proliferate into user code. I can not see why this has even come up for formal review. If this is auseful feature then surely it should be taken up as a core language feature. I would not have such a problem if we had an experimental track and then people could try ideas before making a proposal. We don't have this at the moment and I don't believe this should be accepted into boost. So I vote no. I can't make any other comments on docs, design or implementation etc as I have not looked at it. I am voting no on principle. /ikh

Iain K. Hanson wrote:
I can not see why this has even come up for formal review. If this is auseful feature then surely it should be taken up as a core language feature.
Proposed core language features always stand a better chance when a proof of concept is available. "Look at what monstrocity we had to build in order to get the feature we want" is sometimes a very good argument. :-)

"Peter Dimov" <pdimov@mmltd.net> wrote in message news:001901c54d99$2d738e50$6401a8c0@pdimov2...
Iain K. Hanson wrote:
I can not see why this has even come up for formal review. If this is auseful feature then surely it should be taken up as a core language feature.
Proposed core language features always stand a better chance when a proof of concept is available. "Look at what monstrocity we had to build in order to get the feature we want" is sometimes a very good argument. :-)
That was one of the most effective argument for adding static_assert to the language, IMO. static_assert was voted into the language by the full committee last month in Lillehammer. --Beman

"Beman Dawes" <bdawes@acm.org> wrote in message news:d56h15$2g7$1@sea.gmane.org... | | "Peter Dimov" <pdimov@mmltd.net> wrote in message | news:001901c54d99$2d738e50$6401a8c0@pdimov2... | > Iain K. Hanson wrote: | >> I can not see why this has even come up for formal review. If this is | >> auseful feature then surely it should be taken up as a core language | >> feature. | > | > Proposed core language features always stand a better chance when a proof | > of concept is available. "Look at what monstrocity we had to build in | > order to get the feature we want" is sometimes a very good argument. :-) | | That was one of the most effective argument for adding static_assert to the | language, IMO. | | static_assert was voted into the language by the full committee last month | in Lillehammer. with the exception that Denmark voted against it :-) Anyway, the parallel is good. -Thorsten

Iain K. Hanson wrote:
I really don't like macros.
Can you say why? I ask only because FOREACH doesn't suffer from many of the problems macros typically suffer from.
I have a hard time accepting boost PP but at least we have never before used macros in a way that means that they proliferate into user code.
I can not see why this has even come up for formal review.
Because a number of people have found it useful.
If this is auseful feature then surely it should be taken up as a core language feature.
FOREACH is useful /today/.
I would not have such a problem if we had an experimental track and then people could try ideas before making a proposal.
We do. It's called boost-sandbox. Many of the reviewers have been using FOREACH for a year or more. The code has been publically available in one form or another since 2003.
I am voting no on principle.
Fair enough. -- Eric Niebler Boost Consulting www.boost-consulting.com

Hi Eric, On Sat, Apr 30, 2005 at 10:24:20AM -0700, Eric Niebler wrote:
Iain K. Hanson wrote:
I really don't like macros.
Can you say why? I ask only because FOREACH doesn't suffer from many of the problems macros typically suffer from.
I'm aware of how funcky the work you have done in C++ inside foreach is. I followed the work of you and Dave and Jonathan to try to detect lvalues and rvalues at compile time. I dislike macros not just because of side effects ( and I take your word that this is safe and side-effect free ) but because they obscifate code. II have seen far too much code that is very hard to understand because of macros. If we accept a macro as a lib into boost we are sending a message to the C++ community that macros are o.k. Not only that but we are effective extending the language. And where do we stop. Why not accept awk, perl, and python scripts to re-write our programs. I see little difference.
I have a hard time accepting boost PP but at least we have never before used macros in a way that means that they proliferate into user code.
I can not see why this has even come up for formal review.
Because a number of people have found it useful.
If this is auseful feature then surely it should be taken up as a core language feature.
FOREACH is useful /today/.
No matter how useful, we are condoneing textual re-writing of our code.
I would not have such a problem if we had an experimental track and then people could try ideas before making a proposal.
We do. It's called boost-sandbox. Many of the reviewers have been using FOREACH for a year or more. The code has been publically available in one form or another since 2003.
Yep. But now FOREACH is up for review into the main part of boost. The IETF have an experimental track for RFC's so nobody can confuse something experimental with standards track protocols. boost does not have this. This will be the first time we accept a macro into boost ( aside from boost PP) and I just think this sends the wrong message. Thanks for your reply and I do appreciate the work you do for boost. /ikh

"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote in message news:20050501003902.A21749@titan.hansons.demon.co.uk...
This will be the first time we accept a macro into boost ( aside from boost PP) and I just think this sends the wrong message.
Actually, this isn't true. we accepted BOOST_STATIC_ASSERT into boost quite a while ago. Note that the standards committee is seriously considering adding static assertions to the core (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html). Joe Gottman

On Sat, Apr 30, 2005 at 09:25:44PM -0400, Joe Gottman wrote:
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote in message news:20050501003902.A21749@titan.hansons.demon.co.uk...
This will be the first time we accept a macro into boost ( aside from boost PP) and I just think this sends the wrong message.
Actually, this isn't true. we accepted BOOST_STATIC_ASSERT into boost quite a while ago. Note that the standards committee is seriously considering adding static assertions to the core (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html).
Yes, but BOOST_STATIC_ASSERT is a library writers tool, not really for end users. And the same applies to Concept checking and boost test. I'm familar with the DBC proposal and I hope it makes it into the standard, But I'm not sure how much influence it has had on the proposal or its acceptance. However, I would support a macro in boost if its primary purpose was to support something needed in the standard. And you have no idea how hard it is for me to write that. /ikh

"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote in message news:20050501235133.A23277@titan.hansons.demon.co.uk...
On Sat, Apr 30, 2005 at 09:25:44PM -0400, Joe Gottman wrote:
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote in message news:20050501003902.A21749@titan.hansons.demon.co.uk...
This will be the first time we accept a macro into boost ( aside from boost PP) and I just think this sends the wrong message.
Actually, this isn't true. we accepted BOOST_STATIC_ASSERT into boost quite a while ago. Note that the standards committee is seriously considering adding static assertions to the core (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html).
Yes, but BOOST_STATIC_ASSERT is a library writers tool, not really for end users.
Please don't make me take it out of my applications. :-) Seriously, from my experience, as a non-library-writer, I use it in several places to ensure I don't do something stupid in the future. Jeff Flinn

Yes, but BOOST_STATIC_ASSERT is a library writers tool, not really for end users.
Please don't make me take it out of my applications. :-) Seriously, from my experience, as a non-library-writer, I use it in several places to ensure I don't do something stupid in the future.
FWIW, I _strongly_ second that !

Iain K. Hanson wrote:
This will be the first time we accept a macro into boost ( aside from boost PP) and I just think this sends the wrong message.
The recently accepted Parameter library has macros as part of the public interface. So does the Serialization library, and Concept Check, and probably more.. So this is hardly the first time. -- Daniel Wallin

Daniel Wallin wrote:
Iain K. Hanson wrote:
This will be the first time we accept a macro into boost ( aside from boost PP) and I just think this sends the wrong message.
The recently accepted Parameter library has macros as part of the public interface. So does the Serialization library, and Concept Check, and probably more..
Iostreams too. Jonathan

Iain K. Hanson wrote:
If we accept a macro as a lib into boost we are sending a message to the C++ community that macros are o.k. If one accepts this position, what does he do with when a truely useful and/or necessary facility can only be implemented with a macro? By necesity one must do one of the following:
a) Accept that macros are OK or b) conclude that the facility in question isn't really useful or necessary I don't see any way around this.
Not only that but we are effective extending the language.
Maybe the necessity of a macro points to a direction in which the language needs to be extended. But pending that, we're stuck with a macro.
And where do we stop. Why not accept awk, perl, and python scripts to re-write our programs. I see little difference.
Hmmm - I see no connection here. Robert Ramey

I really don't like macros. I have a hard time accepting boost PP but at least we have never before used macros in a way that means that they
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote proliferate
into user code.
I would probably have agreed with you on this just a year ago. Fortunately, I've been using Boost PP pretty extensively for the last half a year, and my opinion is totaly different now. I think macros, if used appropriately, is a very powerful tool, and together with template metaprogramming represent extremely powerful code generation facility. Code generation will be here, like it or not. You don't like macros, but what's the alternative? MFC wizards? IDL? That's not to say that macros can't be used to obscure things. But any tool may be either useful or harmful, depending on how it's used. Regards, Arkadiy PS: I have a complicated feelings toward BOOST_FOREACH. I've read the article, and I very much like the techniques being used, and how it's done. I do have a problem with the rationale, however. I think both std::for_each, as well as a plain old for loop are just fine, and I don't see why BOOST_FOREACH is better. So, I will probably not use it, at least not right away. But, apparently, many other people will (see the download counter). So I don't vote.

On Sat, Apr 30, 2005 at 02:09:09PM -0700, Arkadiy Vertleyb wrote:
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
I really don't like macros. I have a hard time accepting boost PP but at least we have never before used macros in a way that means that they proliferate into user code.
I would probably have agreed with you on this just a year ago. Fortunately, I've been using Boost PP pretty extensively for the last half a year, and my opinion is totaly different now. I think macros, if used appropriately, is a very powerful tool, and together with template metaprogramming represent extremely powerful code generation facility.
Yes, but until now boosters have kept PP to the implementation of libraries not pushing it out into user code. And PP does obscifate code for those of us that like to look at the implementation of libraries in order to learn. I have a great deal of respect for the PP authors/mainters but it is still textual substitution so why not awk or python scripts.
Code generation will be here, like it or not. You don't like macros, but what's the alternative? MFC wizards? IDL?
Yes, but I thought boost was about quality C++ libraries and showing best C++ practice.
That's not to say that macros can't be used to obscure things. But any tool may be either useful or harmful, depending on how it's used.
Regards, Arkadiy
PS: I have a complicated feelings toward BOOST_FOREACH. I've read the article, and I very much like the techniques being used, and how it's done. I do have a problem with the rationale, however. I think both std::for_each, as well as a plain old for loop are just fine, and I don't see why BOOST_FOREACH is better. So, I will probably not use it, at least not right away. But, apparently, many other people will (see the download counter).
So I don't vote.
Which I respect. Regards /ikh

Yes, but until now boosters have kept PP to the implementation of
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote libraries
not pushing it out into user code. And PP does obscifate code for those of us that like to look at the implementation of libraries in order to learn.
Generating preprocessed code might help.
I have a great deal of respect for the PP authors/mainters but it is still textual substitution so why not awk or python scripts.
Because the preprocessor is built in, which means no external tools is required.
Code generation will be here, like it or not. You don't like macros, but what's the alternative? MFC wizards? IDL?
Yes, but I thought boost was about quality C++ libraries and showing best C++ practice.
And, I hope, it is. However, what is "best C++ practice"? C++ is a multi-paradigm language, and it enabes variety of techniques. IMO this is a strength of C++, and this is what makes it fun, as opposed to some other, very popular, languages. I would even say this is _the_ strength of C++. So making best of these techniques is what makes best C++ practice. IMHO. Regards, Arkadiy

On Sun, May 01, 2005 at 01:08:39AM -0400, Arkadiy Vertleyb wrote:
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
Yes, but until now boosters have kept PP to the implementation of libraries not pushing it out into user code. And PP does obscifate code for those of us that like to look at the implementation of libraries in order to learn.
Generating preprocessed code might help.
Yes, I know but it does involve more that just dropping the code on the printer.
I have a great deal of respect for the PP authors/mainters but it is still textual substitution so why not awk or python scripts.
Because the preprocessor is built in, which means no external tools is required.
Code generation will be here, like it or not. You don't like macros, but what's the alternative? MFC wizards? IDL?
Yes, but I thought boost was about quality C++ libraries and showing best C++ practice.
And, I hope, it is. However, what is "best C++ practice"? C++ is a multi-paradigm language, and it enabes variety of techniques. IMO this is a strength of C++, and this is what makes it fun, as opposed to some other, very popular, languages. I would even say this is _the_ strength of C++. So making best of these techniques is what makes best C++ practice.
Yes but I don't regard the preprocessor as a normally valid part of that multi-paradigm. I am much more in agreement with the views expressed in D&E. /ikh

"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
Yes, but I thought boost was about quality C++ libraries and showing best C++ practice.
And, I hope, it is. However, what is "best C++ practice"? C++ is a multi-paradigm language, and it enabes variety of techniques. IMO this is a strength of C++, and this is what makes it fun, as opposed to some other, very popular, languages. I would even say this is _the_ strength of C++. So making best of these techniques is what makes best C++ practice.
Yes but I don't regard the preprocessor as a normally valid part of that multi-paradigm.
Why? We have a built-in code generation tool, what's wrong with this? Yes, it needs to be improved, for example the lack of recursion is a real pain in the neck. But still, it's very powerfull, and a lot of stuff can be done with it (especially if Boost PP is involved) that otherwise would require either manual repetition or some external code generation tool. Why to abandon this possibility? As far as code readability goes, let me say that template metaprogramming is not very readable either (and therefore considered harmful by many people). I think the reason is that we happen to work in a language where many things are "discovered" rather than "invented". We have templates just to implement typesafe containers, and then suddenly, out of nowhere, we have template metaprogramming, and C++ becomes a two-dimensional language. We have "ugly macros", and then we have preprocessor metaprogramming, which adds yet another dimension. Why things get discovered in C++ but don't get discovered in, say, Java? Because the authors of C++ trust programmers to use the language correctly, rather than trying to prevent mistakes by cutting off features. So, contrary to many other popular languages, C++ is rich, flexible, and extendable. And exciting. Anyway, I am sure macros _are_ OK, if used appropriately. And giving the C++ comunity the message that "macros are OK" would be a right thing (although I think this message was already given some time ago).
I am much more in agreement with the views expressed in D&E.
I am sorry, what is D&E? Regards, Arkadiy

On Sun, 2005-05-01 at 20:55 -0400, Arkadiy Vertleyb wrote:
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
I am much more in agreement with the views expressed in D&E.
I am sorry, what is D&E?
Design and Evolution of C++ by Bjarne Stroustrup.
From the end of chapter 18 "The C Preprocessor " ( last Para ) :
"I'd like to see Cpp abolished. However, the only realistic and responsible way of doing that is first to make it redundant, then encourage people to use the better alternatives, and <em> then </em> - years later - banish Cpp into the program development with the other extra-linguistic tools where it belongs." /ikh _______________________________________________________________________ This email has been scanned for all known viruses by the MessageLabs Email Security System. _______________________________________________________________________

Iain K. Hanson wrote:
Arkadiy Vertleyb wrote:
"Iain K. Hanson" wrote:
I am much more in agreement with the views expressed in D&E.
I am sorry, what is D&E?
Design and Evolution of C++ by Bjarne Stroustrup.
From the end of chapter 18 "The C Preprocessor " ( last Para ) :
"I'd like to see Cpp abolished. However, the only realistic and responsible way of doing that is first to make it redundant, then encourage people to use the better alternatives, and <em> then </em> - years later - banish Cpp into the program development with the other extra-linguistic tools where it belongs."
I basically agree with this, too. But the preprocessor is currently far from redundant, so I don't see this as an argument against BOOST_FOREACH. Jonathan

"Iain K. Hanson" <iain.hanson@videonetworks.com> wrote
Design and Evolution of C++ by Bjarne Stroustrup.
From the end of chapter 18 "The C Preprocessor " ( last Para ) :
"I'd like to see Cpp abolished. However, the only realistic and responsible way of doing that is first to make it redundant, then encourage people to use the better alternatives, and <em> then </em> - years later - banish Cpp into the program development with the other extra-linguistic tools where it belongs."
With all due respect -- this was written more than 11 years ago -- you cannot literally apply this now... Regarding preprocessor -- this is the only built-in code generator in C++, except template metaprogramming, which is limited in this regard. And code generation is crucial for library writers. You don't use preprocessor -- you end up with external tools, like MFC wizards or IDL compiler. I strongly prefer macros. Basically the question is: if you don't use the preprocessor, can you achieve the same without it (external tools don't count) and without violating the DRY principle? If yes, you probably better of without it. If no -- I don't understand the reason to reject macros. Regards, Arkadiy

On Tue, 2005-05-03 at 13:38 -0400, Arkadiy Vertleyb wrote:
"Iain K. Hanson" <iain.hanson@videonetworks.com> wrote
Design and Evolution of C++ by Bjarne Stroustrup.
From the end of chapter 18 "The C Preprocessor " ( last Para ) :
"I'd like to see Cpp abolished. However, the only realistic and responsible way of doing that is first to make it redundant, then encourage people to use the better alternatives, and <em> then </em> - years later - banish Cpp into the program development with the other extra-linguistic tools where it belongs."
With all due respect -- this was written more than 11 years ago -- you cannot literally apply this now...
Why not? The arguments that the chapter uses are as valid today as when written.
Regarding preprocessor -- this is the only built-in code generator in C++, except template metaprogramming, which is limited in this regard. And code generation is crucial for library writers. You don't use preprocessor -- you end up with external tools, like MFC wizards or IDL compiler. I strongly prefer macros.
The preprocessor is NOT a code generator IMHO. It is a textual substitution processor. In some ways I regard external tools as more honest as they do not pretend to be C++ source code.
Basically the question is: if you don't use the preprocessor, can you achieve the same without it (external tools don't count) and without violating the DRY principle? If yes, you probably better of without it. If no -- I don't understand the reason to reject macros.
IMHO external tools that do text substitution are equivilent to the Cpp and do count. If you are after Good ( TM ) code generation tools then I would go for graphical case tools that understand the language and type system. DRY? /ikh _______________________________________________________________________ This email has been scanned for all known viruses by the MessageLabs Email Security System. _______________________________________________________________________

"Iain K. Hanson" <iain.hanson@videonetworks.com> wrote
The preprocessor is NOT a code generator IMHO. It is a textual substitution processor. In some ways I regard external tools as more honest as they do not pretend to be C++ source code.
I don't know what you definition of "code generator" is, but I think, it's what allows to generate code based on some minimal input provided. So, if my user says: REGISTER(foo, (class)(bool)(TEMPLATE(2))); And this is expanded into two template specializations for class template foo, with a class, bool, and template<class, class> class template parameters, one of them capable of serializing an instantiation of such a template into a compile-time vector of integral constants, and another one capable of re-constructing such an instance from this vector, you would not qualify it as "code generation"?
IMHO external tools that do text substitution are equivilent to the Cpp and do count. If you are after Good ( TM ) code generation tools then I would go for graphical case tools that understand the language and type system.
Preprocessor has an obvious advantage of availability to everybody. I, for instance, am very reluctant in downloading/using tools. I suspect many people are like this, too.
DRY?
"Don't repeat yourself". Many tasks would require manual code duplication if not done with Boost PP (which does it for you) Regards, Arkadiy

"Iain K. Hanson" <iain.hanson@videonetworks.com> wrote in message news:1115211567.14534.594.camel@dev-ihanson.ct.uk.videonetworks.com... | On Tue, 2005-05-03 at 13:38 -0400, Arkadiy Vertleyb wrote: | > With all due respect -- this was written more than 11 years ago -- you | > cannot literally apply this now... | | Why not? The arguments that the chapter uses are as valid today as when | written. I think it is fair to say Bjarne would still like to see the preprocessor less used, especially in header files (I'm basing this on proposals like #scope etc). Nevertheless, the preprocessor is a good way to generate some tedious code; just look inside boost.assign. -Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> wrote
Nevertheless, the preprocessor is a good way to generate some tedious code; just look inside boost.assign.
And sometimes, I think, it's _the only_ way. If you are interested, please take a look at typeof_internals.htm.zip in the boost sandbox file vault. Regards, Arkadiy

Arkadiy Vertleyb wrote:
"Thorsten Ottosen" <nesotto@cs.auc.dk> wrote
Nevertheless, the preprocessor is a good way to generate some tedious
code;
just look inside boost.assign.
And sometimes, I think, it's _the only_ way. If you are interested, please take a look at typeof_internals.htm.zip in the boost sandbox file vault.
The only way as long as you commit to not look outside C++. There are plenty of text manipulation tools outside C++ that offer what could be done with the C++ preprocessor with programming paradigms that I consider unworthy of learning. Those tools (sed, awk, perl) are widely available, and in my humble opinion any programmer worth her salt should have at least a cursory understanding of them. Those tools also offer more power than the C++ preprocessor, within the confines of a much more pleasant programming paradigm. (Well don't start an anti-sed war now though. :o)) A line must be drawn somewhere (after all we do use a makefile and not a little C++ program for builds don't we), and I would draw it someplace else than others. For example, if someone doesn't know awk, I'd suggest them to invest time in learning that instead of the boost preprocessor library. So when will the vote result on FOREACH come forth? Andrei

Arkadiy Vertleyb wrote:
And sometimes, I think, it's _the only_ way. If you are interested,
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote please
take a look at typeof_internals.htm.zip in the boost sandbox file vault.
The only way as long as you commit to not look outside C++. There are plenty of text manipulation tools outside C++ that offer what could be done with the C++ preprocessor with programming paradigms that I consider unworthy of learning. Those tools (sed, awk, perl) are widely available, and in my humble opinion any programmer worth her salt should have at least a cursory understanding of them.
Those tools also offer more power than the C++ preprocessor, within the confines of a much more pleasant programming paradigm.
Just out of curiosity: can you write a library that would require to pre-process your user's C++ text with one of these tools, and then convince anybody to use this library? If Perl is better then C++ preprocessor, then it should become C++ preprocessor. But it needs to be built-in, otherwise these are apples against oranges. Regards, Arkadiy

Arkadiy Vertleyb wrote:
Just out of curiosity: can you write a library that would require to pre-process your user's C++ text with one of these tools, and then convince anybody to use this library?
If Perl is better then C++ preprocessor, then it should become C++ preprocessor. But it needs to be built-in, otherwise these are apples against oranges.
I was continuing the following discussion: Thorsten Ottosen: "Nevertheless, the preprocessor is a good way to generate some tedious code; just look inside boost.assign." Arkadiy Vertleyb: "And sometimes, I think, it's _the only_ way. If you are interested, please take a look at typeof_internals.htm.zip in the boost sandbox file vault." Yours Truly: "The only way as long as you commit to not look outside C++." etc. etc. The previous context of the conversation was the preprocessor, not library construction. So I felt that within the conversation my perspective made sense. There are other ways to generate C++ code, and that's what I said and substantiated. On the other hand, I agree with your point made in another post: "Preprocessor has an obvious advantage of availability to everybody. I, for instance, am very reluctant in downloading/using tools. I suspect many people are like this, too." But then if someone continued your argument with: "For example, you won't find on my development systems any of awk, sed, perl and I don't know how to use any of them. However, I am a pp lib expert." then I might opine that that person could reshuffle their priorities. Fair enough? Andrei

"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote
Arkadiy Vertleyb wrote:
Just out of curiosity: can you write a library that would require to pre-process your user's C++ text with one of these tools, and then convince anybody to use this library?
If Perl is better then C++ preprocessor, then it should become C++ preprocessor. But it needs to be built-in, otherwise these are apples against oranges.
I was continuing the following discussion:
Thorsten Ottosen: "Nevertheless, the preprocessor is a good way to generate some tedious code; just look inside boost.assign."
Arkadiy Vertleyb: "And sometimes, I think, it's _the only_ way. If you are interested, please take a look at typeof_internals.htm.zip in the boost sandbox file vault."
Yours Truly: "The only way as long as you commit to not look outside C++." etc. etc.
The previous context of the conversation was the preprocessor, not library construction. So I felt that within the conversation my perspective made sense. There are other ways to generate C++ code, and that's what I said and substantiated.
Well, I thought my mentioning of typeof_internals, as well as the fact that this list _is_ about library construction makes it obvious that we are discussing libraries. Outside the context of library development, I would not recommend anybody to use Boost PP (as well as template metaprogramming, BTW).
On the other hand, I agree with your point made in another post:
"Preprocessor has an obvious advantage of availability to everybody. I, for instance, am very reluctant in downloading/using tools. I suspect many people are like this, too."
But then if someone continued your argument with:
"For example, you won't find on my development systems any of awk, sed, perl and I don't know how to use any of them. However, I am a pp lib expert."
then I might opine that that person could reshuffle their priorities.
Fair enough?
Yes, but what does it have to do with this discussion? Can we convince our users to preprocess their source code with awk? Otherwise I don't understand how the tools you mentioned can be relevant in this context. Regards, Arkadiy

On Wed, May 04, 2005 at 06:49:08PM -0400, Arkadiy Vertleyb wrote:
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote
Well, I thought my mentioning of typeof_internals, as well as the fact that this list _is_ about library construction makes it obvious that we are discussing libraries. Outside the context of library development, I would not recommend anybody to use Boost PP (as well as template metaprogramming, BTW).
So users should not use std::make_pair :-). /ikh

Well, I thought my mentioning of typeof_internals, as well as the fact
this list _is_ about library construction makes it obvious that we are discussing libraries. Outside the context of library development, I would not recommend anybody to use Boost PP (as well as template
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote that metaprogramming,
BTW).
So users should not use std::make_pair :-).
I don't see how using of std::make_pair could qualify as practicing template metaprogramming. Regards, Arkadiy

On Wed, May 04, 2005 at 05:11:05PM -0400, Arkadiy Vertleyb wrote:
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote
If Perl is better then C++ preprocessor, then it should become C++ preprocessor. But it needs to be built-in, otherwise these are apples against oranges.
With all due respect this misses the point completely. We don't need a better text substitution tool for C++. We need something that includes headers, also pragmas, and conditional compilation, the rest IMHO is macro hackery and extra lingustic. /ikh

"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
If Perl is better then C++ preprocessor, then it should become C++ preprocessor. But it needs to be built-in, otherwise these are apples against oranges.
With all due respect this misses the point completely. We don't need a better text substitution tool for C++. We need something that includes headers, also pragmas, and conditional compilation, the rest IMHO is macro hackery and extra lingustic.
And template metaprogramming is just template hackery, correct? I am just trying to understand whether your antipathy is limited to macros, or spreads to everything that was not in the original design, and discovered later? Regards, Arkadiy

On Wed, May 04, 2005 at 09:30:19PM -0400, Arkadiy Vertleyb wrote:
"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
If Perl is better then C++ preprocessor, then it should become C++ preprocessor. But it needs to be built-in, otherwise these are apples against oranges.
With all due respect this misses the point completely. We don't need a better text substitution tool for C++. We need something that includes headers, also pragmas, and conditional compilation, the rest IMHO is macro hackery and extra lingustic.
And template metaprogramming is just template hackery, correct?
No! No! No! now we have type saftey, namespaces, overload sets, dynamic & static polymorphism, metafunctions, and metafunction classes rtc.etc.etc.
I am just trying to understand whether your antipathy is limited to macros, or spreads to everything that was not in the original design, and discovered later?
It's limited to macros. The elegance and in some senses simplicity of static meta programming has a beauty similar to a mathematical proof. The power of C++ is that its original author did not envison all that others might do, but allowed permissively that which need not be denied. /ikh

"Iain K. Hanson" <ikh@hansons.demon.co.uk> wrote
On Wed, May 04, 2005 at 09:30:19PM -0400, Arkadiy Vertleyb wrote: [...]
And template metaprogramming is just template hackery, correct?
No! No! No! now we have type saftey,
Boost PP doesnt compromise type safety...
namespaces,
Agreed, but we can and do approximate them with prefixes...
overload sets, dynamic & static polymorphism,
We can have polymorphism if we want, see my post sometime ago: http://lists.boost.org/MailArchives/boost/msg79530.php. We do use this technique in our BOOST_TYPEOF proposal.
metafunctions, and metafunction classes rtc.etc.etc. [...]
Things change. New techniques get discovered. What used to be "ugly macros" now becomes quite elegant and _very_ useful mechanism, that can be used to achieve things that otherwise ***just cannot be achieved***, and _especially_ if you use macros in the library interface. Why should we throw this away? Regards, Arkadiy

Arkadiy Vertleyb wrote:
Things change. New techniques get discovered. What used to be "ugly macros" now becomes quite elegant and _very_ useful mechanism, that can be used to achieve things that otherwise ***just cannot be achieved***, and _especially_ if you use macros in the library interface. Why should we throw this away?
I agree. Why throw it out? Why not just fix it? It can be fixed. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Those tools also offer more power than the C++ preprocessor, within the confines of a much more pleasant programming paradigm. (Well don't start an anti-sed war now though. :o)) A line must be drawn somewhere (after all we do use a makefile and not a little C++ program for builds don't we),
First of all not all. Relying on awk would make your code non-portable (depend on presence of tool, in proper location, with proper version).
and I would draw it someplace else than others. For example, if someone doesn't know awk, I'd suggest them to invest time in learning that instead of the boost preprocessor library.
I find Boost PP is so much more convinient (IMHO)
So when will the vote result on FOREACH come forth?
Be patient. "Unfortunately" I've got a real-world obligations either. But it's going to be soon.
Andrei
Gennadiy

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
And sometimes, I think, it's _the only_ way. If you are interested, please take a look at typeof_internals.htm.zip in the boost sandbox file vault.
The only way as long as you commit to not look outside C++.
Which is the whole point from a library perspective. Relying on awk (or any other external tool) to write C++ isn't so bad, but relying on it to compile C++ is unacceptable.
There are plenty of text manipulation tools outside C++ that offer what could be done with the C++ preprocessor with programming paradigms that I consider unworthy of learning.
Frankly, without knowing them, you aren't in a position for your opinion to be worth anything. You're a smart guy, Andrei, so the learning curve shouldn't be too difficult for you. Why don't you learn those paradigms and then decide whether they are "worthy" instead of making blanket statements based on nothing? Regards, Paul Mensonides

Paul Mensonides wrote:
The only way as long as you commit to not look outside C++.
Which is the whole point from a library perspective. Relying on awk (or any other external tool) to write C++ isn't so bad, but relying on it to compile C++ is unacceptable.
Fair enough.
There are plenty of text manipulation tools outside C++ that offer what could be done with the C++ preprocessor with programming paradigms that I consider unworthy of learning.
Frankly, without knowing them, you aren't in a position for your opinion to be worth anything. You're a smart guy, Andrei, so the learning curve shouldn't be too difficult for you. Why don't you learn those paradigms and then decide whether they are "worthy" instead of making blanket statements based on nothing?
Oh, that's a misunderstanding. I did learn them. My opinion is based on actual information. I can't claim to be a pp lib expert, but I have an understanding of it. I agree that otherwise an opinion wouldn't be worth anything. So what I was trying to say was, the point at which I will veer away from pp-based programming to other tools happens earlier than others'. Andrei

Andrei Alexandrescu (See Website For Email) wrote:
There are plenty of text manipulation tools outside C++ that offer what could be done with the C++ preprocessor with programming paradigms that I consider unworthy of learning.
Frankly, without knowing them, you aren't in a position for your opinion to be worth anything. You're a smart guy, Andrei, so the learning curve shouldn't be too difficult for you. Why don't you learn those paradigms and then decide whether they are "worthy" instead of making blanket statements based on nothing?
Oh, that's a misunderstanding. I did learn them. My opinion is based on actual information. I can't claim to be a pp lib expert, but I have an understanding of it. I agree that otherwise an opinion wouldn't be worth anything.
So what I was trying to say was, the point at which I will veer away from pp-based programming to other tools happens earlier than others'.
Interesting. At which "point" might that be? For example, which of the PP based libraries in boost would you consider using external tools? Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel wrote:
Andrei Alexandrescu (See Website For Email) wrote:
So what I was trying to say was, the point at which I will veer away from pp-based programming to other tools happens earlier than others'.
Interesting. At which "point" might that be? For example, which of the PP based libraries in boost would you consider using external tools?
My point would be before the PP library itself. I do, however, understand the attraction of having the compile process take care of it all. But "however however", building boost doesn't have to obey that scarcity. So I think it's entirely reasonable that building boost might generate C++ using *other* tools. I bet such an approach would lead to more maintainable and easy-to-understand code (only requiring knowledge of general tools that should be in a boost developer's toolchest anyway) instead of using the PP programming paradigm, of which learning I believe is less rewarding. Cheers, Andrei

"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote
... So I think it's entirely reasonable that building boost might generate C++ using *other* tools. I bet such an approach would lead to more maintainable and easy-to-understand code (only requiring knowledge of general tools that should be in a boost developer's toolchest anyway) instead of using the PP programming paradigm, of which learning I believe is less rewarding.
Interesting... Can you provide an example of how would such a tool generate C++ based on the library user input... Lets just start with the simplest one: the user wants to set maximum size of the mpl::vector<> to 50... Can you explain how that would be achieved with an external tool? Regards, Arkadiy

Arkadiy Vertleyb wrote:
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote
... So I think it's entirely reasonable that building boost might generate C++ using *other* tools. I bet such an approach would lead to more maintainable and easy-to-understand code (only requiring knowledge of general tools that should be in a boost developer's toolchest anyway) instead of using the PP programming paradigm, of which learning I believe is less rewarding.
Interesting... Can you provide an example of how would such a tool generate C++ based on the library user input... Lets just start with the simplest one: the user wants to set maximum size of the mpl::vector<> to 50... Can you explain how that would be achieved with an external tool?
For example, we can have a python script that will generate header files for vector0 .. vector50 given some user supplied configs (with defaults). I remember some people doing that before boost PP became the norm (e.g. boost.python). However... see my other post. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel <joel@boost-consulting.com> wrote: Arkadiy Vertleyb wrote: "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> wrote
... So I think it's entirely reasonable that building boost might generate C++ using *other* tools. I bet such an approach would lead to more maintainable and easy-to-understand code (only requiring knowledge of general tools that should be in a boost developer's toolchest anyway) instead of using the PP programming paradigm, of which learning I believe is less rewarding.
Interesting... Can you provide an example of how would such a tool generate C++ based on the library user input... Lets just start with the simplest one: the user wants to set maximum size of the mpl::vector<> to 50... Can you explain how that would be achieved with an external tool?
For example, we can have a python script that will generate header files for vector0 .. vector50 given some user supplied configs (with defaults). I remember some people doing that before boost PP became the norm (e.g. boost.python).
However... see my other post.
I have a simple problem and will write a trivial cpp program to do it, but perhaps someone has an idea of a better way to do it. The wish is to have a compile time string that is an MPL vector of char so that I can write a compile time parser with certain features. A bit like the xpressive static mode with a bit of spirit thrown in... I can't see a way of doing it nicely with the PP. This strikes me as an example of something that makes you reach for something outside the PP. In this case it is just a simple substitution. Source __cts"a string" Result typedef mpl::vector<char, 'a',' ','s','t','r','i','n','g'> cts_a_string Or some such... Any thoughts? Matt. matthurd@acm.org

"Joel" <joel@boost-consulting.com> wrote
Arkadiy Vertleyb wrote: ...
Interesting... Can you provide an example of how would such a tool generate C++ based on the library user input... Lets just start with the simplest one: the user wants to set maximum size of the mpl::vector<> to 50... Can you explain how that would be achieved with an external tool?
For example, we can have a python script that will generate header files for vector0 .. vector50 given some user supplied configs (with defaults). I remember some people doing that before boost PP became the norm (e.g. boost.python).
Such a little problem, and so much incovenience already... I assume there is no point in moving to more complicated ones ? :-) Regards, Arkadiy

Arkadiy Vertleyb wrote:
"Joel" <joel@boost-consulting.com> wrote
Arkadiy Vertleyb wrote:
...
Interesting... Can you provide an example of how would such a tool
generate
C++ based on the library user input... Lets just start with the
simplest
one: the user wants to set maximum size of the mpl::vector<> to 50...
Can
you explain how that would be achieved with an external tool?
For example, we can have a python script that will generate header files for vector0 .. vector50 given some user supplied configs (with defaults). I remember some people doing that before boost PP became the norm (e.g. boost.python).
Such a little problem, and so much incovenience already... I assume there is no point in moving to more complicated ones ? :-)
Here's what I think. I am trying to encourage everyone - and yes, that includes myself - to think out of the box. It's very easy to say something cannot be done, or can only be done some cumbersome way. But usually, those answers come from straight within the box. And they come with the entire garnishment of irony, sarcasm, "proofs", what have you. But once we stop glorifying the box and decide to get out of it, solutions will be found - and they might even be better. :o) Andrei

"Andrei Alexandrescu (See Website For Email)" wrote
Here's what I think. I am trying to encourage everyone - and yes, that includes myself - to think out of the box. It's very easy to say something cannot be done, or can only be done some cumbersome way. But usually, those answers come from straight within the box. And they come with the entire garnishment of irony, sarcasm, "proofs", what have you. But once we stop glorifying the box and decide to get out of it, solutions will be found - and they might even be better. :o)
Any solution that would 1) allow for non-trivial code generation based on the user input, and 2) would not require end users to download external tools, would be fine with me. Right now I can only see one such solution, but maybe I am missing something. And I am not saying that what we have now is perfect. The biggest problem with PP and Boost PP, IMO, is re-entrancy issues that are caused by the lack of recursion in PP. Just allowing recursion for function-like macros would make our lifes a lot easier. Limitations caused by the fact that inside Boost PP the repetition is done manually, also dont make one too happy. My whole point is, that _today_, despite all the problems, Boost PP proves to be a very poverful tool allowing non-trivial code generation. If something like this existed 10 years ago, we would need neither MFC class wizards nor IDL compiler. Is it "cumbersome"? I don't know -- is template metaprogramming "cumbersome"? I really believe they are very much alike. Both were not in the initial design, both were later discovered, and both are now "glorified" by some people, and hated by the others. IMO, both are not perfect (something seldom is perfect, if it's not in the initial design), but OK -- they allow to achieve pretty interesting effect, especially if used together. Recall, that the discussion started with me trying to argue with the point that "macros are bad because they are bad". I am just saying that today such a point is no longer axiomatic -- it needs to be proven. The prove for me would include providing a better alternative. Regards, Arkadiy

Arkadiy Vertleyb wrote:
Is it "cumbersome"? I don't know -- is template metaprogramming "cumbersome"? I really believe they are very much alike. Both were not in the initial design, both were later discovered, and both are now "glorified" by some people, and hated by the others.
First, the degree of cumbersomeness depends on what those tools are used for. But that's a tautology. Second, I disagree that the template engine and the preprocessor are similar. I see very very little similarity. The former is a mean pure functional language fostering pattern matching, recursion, and sporting knowledge and high integration with the non-templated part of C++. The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years. I don't find the two similar at all, except probably that they both are being used for things they weren't intended for :o). Andrei

Andrei Alexandrescu (See Website For Email) wrote:
Arkadiy Vertleyb wrote:
Is it "cumbersome"? I don't know -- is template metaprogramming "cumbersome"? I really believe they are very much alike. Both were not in the initial design, both were later discovered, and both are now "glorified" by some people, and hated by the others.
First, the degree of cumbersomeness depends on what those tools are used for. But that's a tautology.
Second, I disagree that the template engine and the preprocessor are similar. I see very very little similarity. The former is a mean pure functional language fostering pattern matching, recursion, and sporting knowledge and high integration with the non-templated part of C++. The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years. I don't find the two similar at all, except probably that they both are being used for things they weren't intended for :o).
Ok. As I already mentioned that I used to really hate the PP, you can easily change my mind. I am not particularly fond of the PP but the boost PP lib hides all the ugliness behind a usable interface and that's fine with me. Sure some ugliness cannot be hidden, like, the arcane all cap naming convention prefixed by BOOST_ to avoid name clashes, but... it's the only practical way I know. Ok, please, I'd like to think out of the box! What other alternatives are there? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Ok. As I already mentioned that I used to really hate the PP, you can easily change my mind. I am not particularly fond of the PP but the boost PP lib hides all the ugliness behind a usable interface and that's fine with me. Sure some ugliness cannot be hidden, like, the arcane all cap naming convention prefixed by BOOST_ to avoid name clashes, but... it's the only practical way I know. Ok, please, I'd like to think out of the box! What other alternatives are there?
This is, unsurprisingly, a major effort, and boost would be a crucible of the size and expertise needed to pull it off. The way I see things, there are three ways: 1. Start from the Boost implementation of the C++ preprocessor, and add sane features to it. Keep the old preprocessor features as deprecated. 2. Agree on a standard text preprocessing tool (perl, awk, sed, m4...) and write some utilities tailored for C++ tasks. 3. Start an effort to add ways of manipulating ASTs to the native language so as to eliminate the need for preprocessing. Given, however, the lack of traction that I sense around here, I think this group will be flooded with arguments on why all of 1, 2, and 3 are disadvantageous. But let's stay out of the box :o). Andrei

"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> writes:
This is, unsurprisingly, a major effort, and boost would be a crucible of the size and expertise needed to pull it off.
I think solving the "syntactic metaprogramming problem" really requires familiarity with and access to the source code of a C++ compiler. I don't think we have much of that around here, despite the existence of g++.
The way I see things, there are three ways:
1. Start from the Boost implementation of the C++ preprocessor, and add sane features to it. Keep the old preprocessor features as deprecated.
That one's a possibility. I personally would not want to solve these problems in the preprocessor layer because I want better integration with the rest of the language than that approach can offer. Others may feel differently, of course.
2. Agree on a standard text preprocessing tool (perl, awk, sed, m4...) and write some utilities tailored for C++ tasks.
I've gone down this path, with unsatisfactory results. Not interested in this one.
3. Start an effort to add ways of manipulating ASTs to the native language so as to eliminate the need for preprocessing.
That approach has promise. Bjarne has a project to standardize a C++ program representation and manipulation library -- it could be interesting to build a metaprogramming system around that.
Given, however, the lack of traction that I sense around here, I think this group will be flooded with arguments on why all of 1, 2, and 3 are disadvantageous.
Wow, I guess nobody would want to argue with you on any points for fear of being part of the flood and confirming your "lack of traction." I think until this post of mine showed up, this last sentence had the effect of quashing any further discussion of your three ideas. Instead we have a mostly-irrelevant thread about whether TMP and PPMP are similar. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> writes:
1. Start from the Boost implementation of the C++ preprocessor, and add sane features to it. Keep the old preprocessor features as deprecated.
That one's a possibility. I personally would not want to solve these problems in the preprocessor layer because I want better integration with the rest of the language than that approach can offer. Others may feel differently, of course.
A better integration is not necessarily a good thing -- it's too restrictive. Something like FOREACH, for example (let's pay a tribute to the subject of this discussion), would not be possible in a well-integrated system -- the piece of code it generates is not, by itself, a valid fragment of a C++ program. So a totally independent code generation layer does have its advantages (at least it's more flexible).
3. Start an effort to add ways of manipulating ASTs to the native language so as to eliminate the need for preprocessing.
That approach has promise. Bjarne has a project to standardize a C++ program representation and manipulation library -- it could be interesting to build a metaprogramming system around that.
Well, of course, ultimately it should bring us to something like this, so that we would not have to, for example, instantiate a function template, and take its sizeof() just in order to figure out if one class is derived from another. IMO, it applies to template metaprogramming even more then to PP. I am not too optimistic about this happenning in the near future, though. Regards, Arkadiy

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote
"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> writes:
1. Start from the Boost implementation of the C++ preprocessor, and add sane features to it. Keep the old preprocessor features as deprecated.
That one's a possibility. I personally would not want to solve these problems in the preprocessor layer because I want better integration with the rest of the language than that approach can offer. Others may feel differently, of course.
A better integration is not necessarily a good thing -- it's too restrictive. Something like FOREACH, for example (let's pay a tribute to the subject of this discussion), would not be possible in a well-integrated system
Sure it would.
-- the piece of code it generates is not, by itself, a valid fragment of a C++ program.
That doesn't matter. One possible implementation would be (in a made-up lisp-like language extension): [defmacro foreach [declaration *block] ...] where a parameter called *whatever is expected to be a block of code that syntactically follows the macro invocation. Would you (obviously) want to be able to do that? for example: [defmacro lambda [decl-list *block] ...] for lambda(int x, int y) { whatever }
So a totally independent code generation layer does have its advantages (at least it's more flexible).
That's true. But for that kind of flexibility, we have the PP already ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Andrei Alexandrescu (See Website For Email)" wrote
Arkadiy Vertleyb wrote:
Is it "cumbersome"? I don't know -- is template metaprogramming "cumbersome"? I really believe they are very much alike. Both were not in the initial design, both were later discovered, and both are now "glorified" by some people, and hated by the others.
First, the degree of cumbersomeness depends on what those tools are used for. But that's a tautology.
Second, I disagree that the template engine and the preprocessor are similar. I see very very little similarity. The former is a mean pure functional language fostering pattern matching, recursion, and sporting knowledge and high integration with the non-templated part of C++. The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years. I don't find the two similar at all, except probably that they both are being used for things they weren't intended for :o).
I didn't talk about _similarity_ -- I talked about _analogy_, sorry if it wasn't clear. I am not so strong in theory, and I don't know why token-oriented ideoms are so bad, especially since they are used together with other techniques rather than instead of them. All I see is that PP allows me to solve some issues that I can't solve otherwise. Please give me one good reason why I should not use it. Regards, Arkadiy

"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> writes:
Arkadiy Vertleyb wrote:
Is it "cumbersome"? I don't know -- is template metaprogramming "cumbersome"? I really believe they are very much alike. Both were not in the initial design, both were later discovered, and both are now "glorified" by some people, and hated by the others.
First, the degree of cumbersomeness depends on what those tools are used for. But that's a tautology.
Second, I disagree that the template engine and the preprocessor are similar. I see very very little similarity. The former is a mean pure functional language fostering pattern matching, recursion, and sporting knowledge and high integration with the non-templated part of C++. The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years.
These all sound like moral judgements. Are pattern matching and recursion "good" while token-oriented computation is "bad?" Or are you getting at something else? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
These all sound like moral judgements. Are pattern matching and recursion "good" while token-oriented computation is "bad?"
Or are you getting at something else?
It's not moral judgment. It's simply what kind of language can be understood with each, and what capabilities such a language can offer to its user. Andrei

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
Second, I disagree that the template engine and the preprocessor are similar. I see very very little similarity. The former is a mean pure functional language fostering pattern matching, recursion, and sporting knowledge and high integration with the non-templated part of C++.
What high integration are you referring to here? I don't see much of a high integration between template metaprogramming and the rest of the language. In fact, there is very little integration. Instead, it's more like they coexist without interferring with each other, and communication is entirely one way. Even with the type system, the pattern-matching capabilities are limited to (in essence) syntactic matching rather than more general property matching. You have to bend over backwards to do that (read: SFINAE). So, again, what high integration are you referring to? What I see instead is a lot tricky techniques and a whole slew of specialized idioms to workaround the basic lack of real integration. Don't get me wrong, I'm not condemning template metaprogramming or even specialized idioms and techniques. Rather, the development of those idioms and techniques are laudable examples of people "thinking outside the box" to get something done given the tools that they have. The same applies to preprocessor metaprogramming.
The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years.
What idioms are those? This, BTW, from the perspective of a user, not library internals. What is really the difference, idiomwise, between fold(list, state), fold<list, state>, and FOLD(list, state)? Regards, Paul Mensonides

Paul Mensonides wrote:
The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years.
What idioms are those? This, BTW, from the perspective of a user, not library internals. What is really the difference, idiomwise, between fold(list, state), fold<list, state>, and FOLD(list, state)?
<rant> Speaking of the user's perspective, I find both techniques quite hard to use (with the current tools, i.e. compilers): As soon as I make the slightest error, I'm immediately exposed to all sorts of details through almost unintelligible error messages that *do* require much more knowledge of library internals than I would like. There doesn't appear to be much encapsulation. For example, reading the boost.python tutorial is by far not enough to be able to work with the library. Without reading again and again through reference manual and source code I wouldn't have found my way through all the error messages compilers have been throwing at me. </rant> Regards, Stefan

Paul Mensonides wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
Second, I disagree that the template engine and the preprocessor are similar. I see very very little similarity. The former is a mean pure functional language fostering pattern matching, recursion, and sporting knowledge and high integration with the non-templated part of C++.
What high integration are you referring to here? I don't see much of a high integration between template metaprogramming and the rest of the language. In fact, there is very little integration. Instead, it's more like they coexist without interferring with each other, and communication is entirely one way. Even with the type system, the pattern-matching capabilities are limited to (in essence) syntactic matching rather than more general property matching. You have to bend over backwards to do that (read: SFINAE).
It's not syntactic any day of the week. Not at *all*. Templates perform genuine recursive pattern matching. They feed on types and constants and offer types and constants back. I see good integration there. If, on the other hand, you want to discuss the limited amount of introspection C++ offers, that's a different subject.
So, again, what high integration are you referring to? What I see instead is a lot tricky techniques and a whole slew of specialized idioms to workaround the basic lack of real integration. Don't get me wrong, I'm not condemning template metaprogramming or even specialized idioms and techniques. Rather, the development of those idioms and techniques are laudable examples of people "thinking outside the box" to get something done given the tools that they have. The same applies to preprocessor metaprogramming.
The computational model is known and powerful. In contrast, programming based on the token-oriented preprocessor uses arcane idioms and computations, which IMO just takes us back 40 years.
What idioms are those? This, BTW, from the perspective of a user, not library internals. What is really the difference, idiomwise, between fold(list, state), fold<list, state>, and FOLD(list, state)?
I am referring to idioms that ask you to #define certain things and then invoke macros that will use them (or worse, include files that will use them!) and then #undef them, or that have you define files that rely on things like "I am iterating now through this file", all that comma handling, the necessarily long names, the dynamic binding (a historical mistake that keeps on coming again and again in PL design! yuck!) etc. IMHO those idioms' place is in programming language history books as "awkward first attempts". Andrei

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
What high integration are you referring to here? I don't see much of a high integration between template metaprogramming and the rest of the language. In fact, there is very little integration. Instead, it's more like they coexist without interferring with each other, and communication is entirely one way. Even with the type system, the pattern-matching capabilities are limited to (in essence) syntactic matching rather than more general property matching. You have to bend over backwards to do that (read: SFINAE).
It's not syntactic any day of the week. Not at *all*.
There is a near direct correlation between syntax and its capabilities. I don't mean that it literally is syntactic matching. It can only match those type properties that can be formed syntactically--and it cannot even match all of those. Furthermore, the primary utility of that pattern matching is with templates themselves, not the "non-template part of C++." The template mechanism alone (meaning without major hacks) cannot do even the simplest manipulation on the non-template part. Even with major hacks, it can still only do a very limited amount of such manipulation. Other than a few commonalities (like name binding), there is virtually no integration between the two. The non-template part can statically cause the instantiation of a template and dynamically use it, and the template mechanism can statically introduce non-template code, but the template mechanism cannot statically invoke the non-template part, nor can the non-template part dynamically cause the instantiation of a template. There are only two types of communication, and, from the template side in particular, it is only one-way communication. That isn't integration, that is a layered separation. For metaprogramming, the template mechanism is usable (and a lot of interesting things can be done using it), but it is not robust.
Templates perform genuine recursive pattern matching. They feed on types and constants and offer types and constants back. I see good integration there.
The mechanism is systematic, but that doesn't say anything about its integration with the non-template part of C++.
If, on the other hand, you want to discuss the limited amount of introspection C++ offers, that's a different subject.
No, it really isn't a different subject. We are talking about metaprogramming, not simplistic type substitution ("regular" template usage). There are two purposes of metaprogramming: introspection and generation (i.e. generative metaprogramming). The template mechanism is only mediocre at both. BTW, I'm not saying that the preprocessor does better overall. The preprocessor is terrible at introspection, but (comparatively) excels at many types of generation. There are serious strengths and weaknesses in both mechanisms.
What idioms are those? This, BTW, from the perspective of a user, not library internals. What is really the difference, idiomwise, between fold(list, state), fold<list, state>, and FOLD(list, state)?
I am referring to idioms that ask you to #define certain things and then invoke macros that will use them (or worse, include files that will use them!) and then #undef them
Which is no different than limiting scope in any other context. How many people, for example, complain about the internal linkage of local structures which could otherwise be used for function objects (etc.)? When you write such a #define (in the context of metaprogramming), you are defining a function, which, in the case above, is passed to a higher-order algorithm. The #undef merely explicitly controls the lifetime of the function. In some ways, the preprocessor treats such 'functions' as first class objects better than the core language does.
, or that have you define files that rely on things like "I am iterating now through this file",
What is wrong with that? More specifically, what is wrong with viewing the preprocessing pass as a sort of script execution? That is exactly what it is. In fact, parsing non-preprocessor C++ is itself a sort of top-to-bottom script execution (e.g. function prototypes, predeclarations, etc.). Thinking of it any other way is, with C++ in its current form, fundamentally flawed.
all that comma handling,
There is actually very little comma handling in real preprocessor code. Granted, there is some, but with variadics, the difficulty in handling those nearly disappears--as I showed you before. Having to write TYPELIST(int, (std::pair<int, int>), double) is not that much of a burden. As I've also said before, the preprocessor's primary strength is its disassociation with the underlying language--for generation, the syntax and semantics of the generated language interfere**. That is also its primary weakness--it cannot do any realistic introspection into the syntax and semantics of the underlying language. Commas are a mildly annoying case entirely because a particular part of the syntax of the preprocessor is colliding with a particular part of the syntax of the underlying language. ** This is both a good thing and a bad thing. It is a good thing because you can directly express the generation. Syntactic (and semantic) integration leads to roundabout generation. On the other hand, syntactic integration allows for uniform syntax--which, in turn, allows for infinite "meta-levels" (i.e. metacode that operates on metacode (etc.) which operates on runtime code).
the necessarily long names,
For library facilities, yes. You need to apply a namespace. That isn't really that different than normal C++, except when actually designing the library facilities. In normal client C++, you can explicitly qualify names or manually bring them into scope. You can do the same things with the preprocessor. (There are also a variety of ways of locally shortening names without defining macros.)
the dynamic binding (a historical mistake that keeps on coming again and again in PL design! yuck!) etc.
...which hardly matters when there is no lexical scoping or namespaces/packages. Dynamic versus static binding is irrelevant when a symbol unambiguously refers to a distinct entity.
IMHO those idioms' place is in programming language history books as "awkward first attempts".
On of the most effective aspects of the preprocessor, BTW, is that there is no fundamental distinction between input/output and argument/return value (i.e. A() produces output, but the A() in B(A()) produces a return value). This lack of distinction eliminates a great deal of cruft in the generation process. If you do it in another language (i.e. external tool), you have to distinguish between them--which is more verbose. The preprocessor is naturally more domain-specialized for generation than existing external (general purpose) tools. Granted, you could define such abstractions in another language (or define another language), but that would eventually lead you nearly full circle--you'd end up with a custom preprocessor that does similar things. Yes, by throwing out other important considerations, you could make it better. Now, improving the preprocessor (as you and Joel both mention) is a much better alternative. However, I, for one, won't use non-standard extensions unless there is 1) no other way or 2) using them is drastically better than the alternative. There isn't much that you can do to the preprocessor to make it better to that extent. What that means is that the improvements need to be standardized--and the main thing preventing that is the common "wisdom" that the use of macros is evil--for whatever reasons (or lack of reasons). In other words, your approach leads to a circular non-solution. Denouncing the preprocessor is not going to lead to a better preprocessor. Improving the preprocessor requires first swaying the general opinion on preprocessor-like use (the hard part--an upcliff battle) and then move to add or update features (the easy part). Regards, Paul Mensonides

Andrei Alexandrescu (See Website For Email) wrote:
Joel wrote:
Andrei Alexandrescu (See Website For Email) wrote:
So what I was trying to say was, the point at which I will veer away from pp-based programming to other tools happens earlier than others'.
Interesting. At which "point" might that be? For example, which of the PP based libraries in boost would you consider using external tools?
My point would be before the PP library itself. I do, however, understand the attraction of having the compile process take care of it all. But "however however", building boost doesn't have to obey that scarcity. So I think it's entirely reasonable that building boost might generate C++ using *other* tools. I bet such an approach would lead to more maintainable and easy-to-understand code (only requiring knowledge of general tools that should be in a boost developer's toolchest anyway) instead of using the PP programming paradigm, of which learning I believe is less rewarding.
I think you are assuming that there's always something to "build". Yeah, I agree that would be ok (***). OTOH, lots of parts of the boost libraries do not require building at all since they are "all header". (***) aside: such an approach would lead to more maintainable and easy-to-understand code IFF we agree on a specific code generation tool. Otherwise, we'll end up with lots of tiny languages which will ultimately defeat the maintainability and understandability goal. Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@moderncppdesign.com> writes:
So what I was trying to say was, the point at which I will veer away from pp-based programming to other tools happens earlier than others'.
FWIW, long ago I veered away and found it to be much worse over in that world. I wrote a special Python-based code template processing engine to generate code for Boost.Python. The result was that -- despite my best efforts -- the inputs were not significantly more readable or debuggable than what I have today using the PP, and the result had significant disadvantages. I'm very happy to have Boost.Python back in the 100% C++ land it occupies today. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Paul Mensonides wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
And sometimes, I think, it's _the only_ way. If you are
interested,
please take a look at typeof_internals.htm.zip in the boost
sandbox file vault.
The only way as long as you commit to not look outside C++.
Which is the whole point from a library perspective. Relying on awk (or any other external tool) to write C++ isn't so bad, but relying on it to compile C++ is unacceptable.
One does not rely on the preprocessor to compile C++. Andrei's argument was that these tools can be used to create C++ code, not compile them. However I would argue with Andrei ( you forgot Python among your tools BTW ) that while these tools might be able to create C++ code, it is currently far more difficult to use them to do that than it is to use the C++ preprocessor, largely becaause of lack of code in these tools to do so. Also, of course, you would need to convince the C++ standards people that some other tool, as you mentioned, should be integrated into the C++ compiler to replace the C++ preprocessor as a pre-compiler code generator. Good luck !

Edward Diener wrote:
Paul Mensonides wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
The only way as long as you commit to not look outside C++.
Which is the whole point from a library perspective. Relying on awk (or any other external tool) to write C++ isn't so bad, but relying on it to compile C++ is unacceptable.
One does not rely on the preprocessor to compile C++. Andrei's argument was that these tools can be used to create C++ code, not compile them.
The point is that when a library uses macros in its public interface, the code generation takes place when the library user's code is compiled. Jonathan

On Wed, May 04, 2005 at 02:14:59PM -0700, Paul Mensonides wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Andrei Alexandrescu (See Website For Email)
And sometimes, I think, it's _the only_ way. If you are interested, please take a look at typeof_internals.htm.zip in the boost sandbox file vault.
The only way as long as you commit to not look outside C++.
Which is the whole point from a library perspective. Relying on awk (or any other external tool) to write C++ isn't so bad, but relying on it to compile C++ is unacceptable.
Noooh! The preprocessor has nothing to do with C++ except historical accident. And very little to do with compilation. Straight text substitution is not a good way forward and leads to obscifation. The onl good use of macros is to highlight weaknesses in the language that need to be rectified. Perhaps the best of these where mpl::containers need variable size. /ikh

The only way as long as you commit to not look outside C++. There are plenty of text manipulation tools outside C++ that offer what could be done with the C++ preprocessor with programming paradigms that I consider unworthy of learning. Those tools (sed, awk, perl) are widely available, and in my humble opinion any programmer worth her salt should have at least a cursory understanding of them.
I've experimented with using PHP and C++ together, with good success. The nice thing about PHP is it lives inside my C++ source code, see a mini example [1] below. In the biggest real-world test of this I had a big PHP array of PHP objects, each object describing some algorithm. In my make file (actually scons) I compiled my "X.cpp.php" file into "X.cpp", which was then compiled by g++. Some issues I had: 1. I had to keep switching my editor between PHP syntax hilighting and C++ syntax. I could get around this by writing a syntax hilighter file for my editor. 2. I had to remember to edit the X.cpp.php file, not the X.cpp file. I got around this a bit by having scons make the X.cpp file read-only. 3. Line numbers of error messages. I guess they can all be summarized as lack of tool support. Darren [1] //Normal C++ code here <?php $types=Array('int','double','custom_type'); foreach($types as $t){ ?> <?php echo $t;?> generator_of_<?php echo $t;?>(int id){ //... <?php if($t)=='custom_type'){ ?> //Special code to make custom_type <?php }else{ ?> //Code to make built-in type <?php } ?> } //End of the generator_of_* functions <?php } ?> //More normal C++ code here

Andrei Alexandrescu wrote:
Those tools also offer more power than the C++ preprocessor, within the confines of a much more pleasant programming paradigm. (Well don't start an anti-sed war now though. :o)) A line must be drawn somewhere (after all we do use a makefile and not a little C++ program for builds don't we), and I would draw it someplace else than others. For example, if someone doesn't know awk, I'd suggest them to invest time in learning that instead of the boost preprocessor library.
FYI, Wave has a special #pragma usable for bridging this gap: #pragma wave system(any OS command) which spawns of the given command and intercepts the produced stdout stream, inserting it instead of the pragma itself :-P. In C99 mode you even may use it from the operator _Pragma and force a full macro expansion of the inserted results: #define EVAL(x) x EVAL(_Pragma("wave system(any OS command)")) Regards Hartmut

Hartmut Kaiser wrote:
FYI, Wave has a special #pragma usable for bridging this gap:
#pragma wave system(any OS command)
which spawns of the given command and intercepts the produced stdout stream, inserting it instead of the pragma itself :-P. In C99 mode you even may use it from the operator _Pragma and force a full macro expansion of the inserted results:
#define EVAL(x) x EVAL(_Pragma("wave system(any OS command)"))
Regards Hartmut
Hartmut, is that a good idea? I can imagine that running an existing executable might cause untold damage to my system, but compiling a piece of source code? Doesn't it smack of C++ source code as computer virus? Regards, Angus

Angus Leeming wrote:
Hartmut Kaiser wrote:
FYI, Wave has a special #pragma usable for bridging this gap:
#pragma wave system(any OS command)
which spawns of the given command and intercepts the produced stdout stream, inserting it instead of the pragma itself :-P. In C99 mode you even may use it from the operator _Pragma and force a full macro expansion of the inserted results:
#define EVAL(x) x EVAL(_Pragma("wave system(any OS command)"))
Regards Hartmut
Hartmut,
is that a good idea? I can imagine that running an existing executable might cause untold damage to my system, but compiling a piece of source code?
Doesn't it smack of C++ source code as computer virus?
Well, technically, being templates turing complete we are in trouble anyway ... Sorry couldn't resist :) -- Giovanni P. Deretta

On May 5, 2005, at 11:51 AM, Giovanni P. Deretta wrote:
Angus Leeming wrote:
FYI, Wave has a special #pragma usable for bridging this gap:
#pragma wave system(any OS command)
which spawns of the given command and intercepts the produced stdout stream, inserting it instead of the pragma itself :-P. In C99 mode you even may use it from the operator _Pragma and force a full macro expansion of the inserted results:
#define EVAL(x) x EVAL(_Pragma("wave system(any OS command)"))
Regards Hartmut Hartmut, is that a good idea? I can imagine that running an existing executable might cause untold damage to my system, but compiling a
Hartmut Kaiser wrote: piece of source code? Doesn't it smack of C++ source code as computer virus?
Well, technically, being templates turing complete we are in trouble anyway ...
Sorry couldn't resist :)
A program running on a Turing machine can only affect the tape of the machine. The "tape" of a template metaprogram is quite well isolated from other parts of a computer system. (OTOH, templates never cease to surprise...) Jaakko

jarvi wrote:
A program running on a Turing machine can only affect the tape of the machine. The "tape" of a template metaprogram is quite well isolated from other parts of a computer system. (OTOH, templates never cease to surprise...)
Jaakko
Yes, of course (i was jocking :) ) ... ... but probably templates are not so "quite well" isolated from the rest of the computer system, consider an extremely convoluted template that crashes a compiler. Such a crash might be exploitable to run arbitrary code. Certanly it wouldn't be easy and definitelly it would be not portable, but certanly it may happen. (of course compilers may crash not only while handling templates, but this is certanly much more likely ;) ) This is obviously purely accademic, because makefiles or jamfiles are certanly a better place to put malicious code :). -- Giovanni P. Deretta

Angus Leeming wrote:
FYI, Wave has a special #pragma usable for bridging this gap:
#pragma wave system(any OS command)
which spawns of the given command and intercepts the produced stdout stream, inserting it instead of the pragma itself :-P. In C99 mode you even may use it from the operator _Pragma and force a full macro expansion of the inserted results:
#define EVAL(x) x EVAL(_Pragma("wave system(any OS command)"))
Regards Hartmut
Hartmut,
is that a good idea? I can imagine that running an existing executable might cause untold damage to my system, but compiling a piece of source code?
Doesn't it smack of C++ source code as computer virus?
Well, you still need to have the 'appropriate' executable to run to make it into a virus. And, BTW, this was a feature request for Wave during its development. But I may include the corresponding code based on a preprocessor directive only, so by default this wouldn't be compiled in ... :-P Regards Hartmut

FYI, Wave has a special #pragma usable for bridging this gap:
#pragma wave system(any OS command)
which spawns of the given command and intercepts the ... Doesn't it smack of C++ source code as computer virus?
Well, you still need to have the 'appropriate' executable to run to make it into a virus.
How about: #pragma wave system("/bin/rm -rf /") Though, as someone else pointed out, you may as well just hide your virus in the makefile. Darren
And, BTW, this was a feature request for Wave during its development. But I may include the corresponding code based on a preprocessor directive only, so by default this wouldn't be compiled in ... :-P
Regards Hartmut

"Arkadiy Vertleyb" <vertleyb@hotmail.com> writes:
"I'd like to see Cpp abolished. However, the only realistic and responsible way of doing that is first to make it redundant, then encourage people to use the better alternatives, and <em> then </em> - years later - banish Cpp into the program development with the other extra-linguistic tools where it belongs."
With all due respect -- this was written more than 11 years ago -- you cannot literally apply this now...
Bjarne hasn't changed his mind, FWIW. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d4j89a$cd7$1@sea.gmane.org... | The formal review of Eric Nibbler's FOREACH macro starts today, April 25, | and will continue until Monday, May 1st. I will be serving as review | manager. | | BOOST_FOREACH is a macro that makes it simple to iterate over STL | containers, ranges, arrays and null-terminated strings. Its performance | approaches that of the hand-coded equivalent loop. BOOST_FOREACH uses | Boost.Range can be extended to iterating user-defined collections by | extending Boost.Range. | | The library is available at: | | http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler | foreach.zip is there any reason we're not rewieving in range_ex at the same time? -Thorsten

Thorsten Ottosen wrote:
"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d4j89a$cd7$1@sea.gmane.org... | The formal review of Eric Nibbler's FOREACH macro starts today, April 25, | and will continue until Monday, May 1st. I will be serving as review | manager.
is there any reason we're not rewieving in range_ex at the same time?
-Thorsten
Because they're different libraries ... ? What makes you think they should be reviewed together? I should also point out that FOREACH is ready and useful today, whereas range_ex has major outstanding design questions. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4270186E.20907@boost-consulting.com... | | Thorsten Ottosen wrote: | > "Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message | > news:d4j89a$cd7$1@sea.gmane.org... | > | The formal review of Eric Nibbler's FOREACH macro starts today, April 25, | > | and will continue until Monday, May 1st. I will be serving as review | > | manager. | > | > is there any reason we're not rewieving in range_ex at the same time? | > | > -Thorsten | > | | | Because they're different libraries ... ? What makes you think they | should be reviewed together? they have some parts in commen. | I should also point out that FOREACH is ready and useful today, whereas | range_ex has major outstanding design questions. which are those btw? -Thorsten

Thorsten Ottosen wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4270186E.20907@boost-consulting.com...
| I should also point out that FOREACH is ready and useful today, whereas | range_ex has major outstanding design questions.
which are those btw?
-Thorsten
Documented here: http://tinyurl.com/957z9, but in short: * Output ranges or output iterators? * For algos that take 2 sequences, take 2 ranges or a range and an iterator? * Should find(map) call map.find()? * When using the range algos to copy chars, do we try to ensure null-termination? -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4270F421.8040806@boost-consulting.com... | Thorsten Ottosen wrote: | > "Eric Niebler" <eric@boost-consulting.com> wrote in message | > news:4270186E.20907@boost-consulting.com... | > | > | I should also point out that FOREACH is ready and useful today, whereas | > | range_ex has major outstanding design questions. | > | > which are those btw? | > | > -Thorsten | > | | | Documented here: http://tinyurl.com/957z9, but in short: | | * Output ranges or output iterators? We have eg. template<class InIt, class OutIt> OutIt copy(InIt first, InIt last, OutIt dest); template<typename Rng, typename OutIter> OutIter copy(Rng const &, OutIter); Should the latter then take an OutputRange (whatever that means)? I guess that is not a bad idea; Let's say an out-put Range defines this function: template< class I > iterator insert( I beg, I end ); Then we could define copy() like this: template< class InputRng, class OutputRng > typename range_iterator<OutputRng>::type copy( const InputRng& in, OuputRng out ) { out.insert( begin(in), end(in) ); } Then we could call copy() it like this: list<int> in; vector<int> out; copy( in, range_back_inserter(out) ); list<int> in; int array[] = { ... }; copy( in, range_overwriter( array ) ); always safe and fast. Alternatively, we could introduce a new function in the output iterator a. la. insert() above; then we could define a tag and require algorithms to dispatch to different implementation of the algos. This might not seem like too clever. | * For algos that take 2 sequences, take 2 ranges or a range and an iterator? Like in template<typename Rng1, typename Rng2> BOOST_DEDUCED_TYPENAME boost::range_iterator< Rng1 >::type search(Rng1 &, Rng2 const &); ? What use would it be to only have an iterator? | * Should find(map) call map.find()? no IMO. The algorithms are different in complexity. | * When using the range algos to copy chars, do we try to ensure | null-termination? As I see it, we just have to pick one default and stick with that. Boost.Range does not include the null in the length of the string; I think that is acceptable. Perhaps a special adapter that automatically searches for a null and/or includes it in the range can be provided: copy( null_string_range( a_string ), ... ); -Thorsten

| > | I should also point out that FOREACH is ready and useful today, whereas | > | range_ex has major outstanding design questions. | > | > which are those btw?
I believe we should move this discussion into separate thread. FOREACH is under review now and range_ex is not even requested yet. If we want it to be reviewed the first step in this direction could be to request one. Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d4r15n$h34$1@sea.gmane.org... |> | > | I should also point out that FOREACH is ready and useful today, | > whereas | > | > | range_ex has major outstanding design questions. | > | > | > | > which are those btw? | | I believe we should move this discussion into separate thread. FOREACH is | under review now and range_ex is not even requested yet. If we want it to be | reviewed the first step in this direction could be to request one. Then I request a review :-) Eric, please just respond privately or in a new thread. -Thorsten

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d4j89a$cd7$1@sea.gmane.org... | When submitting reviews, please state explicitly whether or not you believe | that the library should be accepted into Boost. Yes, this library should be accepted. I've looked at documentation before the review and even then it was of high quality. The library fills a little gab in the C++ language and does it really well. -Thorsten

| When submitting reviews, please state explicitly whether or | not you believe that the library should be accepted into Boost. Yes, this library should be accepted. Based mainly on what others have reported. I don't buy the argument that we should not encourage any macro based submissions, (even though I go 'ugh' every time I see a macro). On the contrary, I think that establishing a need through macro usage should facilitate C++ language change. (Following the precedents of named parameters, typeof... that highlight obvious language needs). But since the rate of language change is so glacial, (a serious problem IMO) very many people can make use of it in the meantime. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

Hi, Let me step out of review manager role for a moment and give actual review. As many of you here I fell in love with this utility macro the moment I heard about it. Many would agree that lack of expressiveness in lambda expression generation is a major drawback in current STL design. Boost.Lambda does address part of the issue. But I still believe BOOST_FOREACH is more portable, powerfull and easier to use. Regrdless to what I am going to say later I believe this macro would be a valueable addition and should be accepted. Here is a couple remarks I wanted to make. First a general one: I believe FOREACH is so widely usefull it should work for all compilers we do our resression tests (with different levels of compartibility). Actually as some of you may noticed I implemented version of FOREACH internally in Boost.Test namely because I need portable version, while I liked to use FOREACH. Once (if) BOOST_FOREACH implementation is made portable for my purposes I would be willing to get rid of my version. As it stands now here are results for resress.cpp test (compilers I could test on): borland 5.5.1 - fail borland 5.6.4 - fail cw-8.3 - fail gcc 3.3.3 - pass Intel 8.1 - pass gcc 2.95 - fail vc 6.5 - fail vc 6.5 (stlport) - fail vc 7.1 - pass vc 7.1 (stlport) - pass sunpro 5.3 - fail Now for some specific issues: 1. Rvalues support I agree it's cool and "magical" - the way you added support for rvalues. But I believe it's actually misplaced efforts. IMO support for rvalues brings more harm than advantage. I could accidently or mindlessly (using some global replacement in sources, for example) introduce rvalue in BOOST_FOREACH statement and compiler wouldn't warn me. Now I am paying for an unnessesary copying. while exist perfectly good alternative that doesn't require it: my_collection_type my_function(); ... my_collection_type const& v = my_function() BOOST_FOREACH(... , v ) { } In addition eliminating rvalues support will signicantly simplify implementation and as a result speed up compilation. 2. Usage of Boost.Range I understand why FOREACH is using Boost.Range, but: a) In many (most) cases I (and any other developer now) working with stl containers and wouldn't need any extra help from boost.range for FOREACH to work properly. b) Usage of Boost.Range introduces an extra dependency on ... Boost.Range and everything it depends on in its' turn (including all portability limitations). I for one couldn't afford this dependency, c) Usage of Boost.Range adding a level of indiration and slightly complicate am implementation I am not going to propose to eliminate this dependency completely. But I think we need to make it optional. Users shouldn't pay for what they do not need (in most/many cases). Also I believe some old compilers could only made to work in such mode. So you may introduce another level of compartibility - working only with stl compartible container-lvalue. As to what should be the default - it's your call. 3. regress.cpp I do not see test program testing all the cases (rvalue canst collections etc). You may want to create several test files for each level of compartibility 4. auto_any auto_any staff deserves at least special mentionning in docs (if not separate header). If should explain the tecnique and how it could be used 5. type2type I believe we already have something similar in boost. 6. typeof/encode_type I believe this tecnique desirves separat eheader and special explantion in docs. 7. First elem support FOREACH could easily add support for the first element detection. I think it may be wrty addition. In any case thanks for making it available for us. Regards, Gennadiy

Gennadiy Rozental wrote:
1. Rvalues support I agree it's cool and "magical" - the way you added support for rvalues. But I believe it's actually misplaced efforts. IMO support for rvalues brings more harm than advantage. I could accidently or mindlessly (using some global replacement in sources, for example) introduce rvalue in BOOST_FOREACH statement and compiler wouldn't warn me. Now I am paying for an unnessesary copying. while exist perfectly good alternative that doesn't require it:
my_collection_type my_function(); ...
my_collection_type const& v = my_function()
BOOST_FOREACH(... , v ) { }
In addition eliminating rvalues support will signicantly simplify implementation and as a result speed up compilation.
There is an important usage scenario that requires iteration over rvalue containers ... when you don't know the type of the container. With the ragex_lib (in boost-sandbox), you can filter and transform a range *in place* and then immediately iterate over it. Consider: BOOST_FOREACH(..., v | filter(my_pred()) | transform(my_func())) { } Here, filter and transform are range adaptors, built on top of filter_iterator and transform_iterator. The type of the container is complicated, but you don't have to mention it anywhere because FOREACH correctly handles rvalues. This is very powerful.
2. Usage of Boost.Range
I understand why FOREACH is using Boost.Range, but: a) In many (most) cases I (and any other developer now) working with stl containers and wouldn't need any extra help from boost.range for FOREACH to work properly. b) Usage of Boost.Range introduces an extra dependency on ... Boost.Range and everything it depends on in its' turn (including all portability limitations). I for one couldn't afford this dependency, c) Usage of Boost.Range adding a level of indiration and slightly complicate am implementation
Actually, I switched to Boost.Range to make the implementation *less* complicated.
I am not going to propose to eliminate this dependency completely. But I think we need to make it optional.
What do you mean by and optional dependency on Boost.Range? Users shouldn't pay for what they do not
need (in most/many cases). Also I believe some old compilers could only made to work in such mode. So you may introduce another level of compartibility - working only with stl compartible container-lvalue. As to what should be the default - it's your call.
I need to document how to extend FOREACH. Either it is done by extending Boost.Range, or it's done another way. Not sure how an "optional" dependeny on Boost.Range fits in to that.
3. regress.cpp I do not see test program testing all the cases (rvalue canst collections etc). You may want to create several test files for each level of compartibility
Agreed.
4. auto_any
auto_any staff deserves at least special mentionning in docs (if not separate header). If should explain the tecnique and how it could be used
I consider this an implementation detail. I would rather keep it that way until there is a need to break it out, at which point ... maybe a fast-track review or something.
5. type2type
I believe we already have something similar in boost.
6. typeof/encode_type I believe this tecnique desirves separat eheader and special explantion in docs.
Also an implementation detail. I would be hesitatnt to break it out unless someone demonstrated a need.
7. First elem support FOREACH could easily add support for the first element detection. I think it may be wrty addition.
Putting an extra bool on the stack and maintaining its state is overhead that not everyone should have to pay for, IMO. I don't think enough people would use it to justify the expense, especially considering that it's easy enough to use your own bool to detect the first element: bool first = true; BOOST_FOREACH(....) { if(first) { do_something(); first = false; } }
In any case thanks for making it available for us.
My pleasure. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4276407E.6030205@boost-consulting.com...
Gennadiy Rozental wrote:
1. Rvalues support I agree it's cool and "magical" - the way you added support for rvalues. But I believe it's actually misplaced efforts. IMO support for rvalues brings more harm than advantage. I could accidently or mindlessly (using some global replacement in sources, for example) introduce rvalue in BOOST_FOREACH statement and compiler wouldn't warn me. Now I am paying for an unnessesary copying. while exist perfectly good alternative that doesn't require it:
my_collection_type my_function(); ...
my_collection_type const& v = my_function()
BOOST_FOREACH(... , v ) { }
In addition eliminating rvalues support will signicantly simplify implementation and as a result speed up compilation.
There is an important usage scenario that requires iteration over rvalue containers ... when you don't know the type of the container. With the ragex_lib (in boost-sandbox), you can filter and transform a range *in place* and then immediately iterate over it. Consider:
BOOST_FOREACH(..., v | filter(my_pred()) | transform(my_func())) { }
Hopefully soon enough we may be able to write auto const& r = v | filter(my_pred()) | transform(my_func()); BOOST_FOREACH(..., r ) { }
Here, filter and transform are range adaptors, built on top of filter_iterator and transform_iterator. The type of the container is complicated, but you don't have to mention it anywhere because FOREACH correctly handles rvalues.
This is very powerful.
And dangerous. Cause allows developer to "forget" about an extra copy. I guess I could live with it. I wrap it into my own header and disable rvalues by definining appropriate macros
2. Usage of Boost.Range
I understand why FOREACH is using Boost.Range, but: a) In many (most) cases I (and any other developer now) working with stl containers and wouldn't need any extra help from boost.range for FOREACH to work properly. b) Usage of Boost.Range introduces an extra dependency on ... Boost.Range and everything it depends on in its' turn (including all portability limitations). I for one couldn't afford this dependency, c) Usage of Boost.Range adding a level of indiration and slightly complicate am implementation
Actually, I switched to Boost.Range to make the implementation *less* complicated.
It adds a level of indirection, right. You are using Boost.Range for support legacy arrays and extencibility. If you would stick with col.begin() and col.end() it would be simpler.
I am not going to propose to eliminate this dependency completely. But I think we need to make it optional.
What do you mean by and optional dependency on Boost.Range?
#ifndef BOOST_FOREACH_NO_BOOST_RANGE_DEPENDENCY or #ifndef BOOST_FOREACH_NO_EXTENCIONS Gennadiy

Gennadiy Rozental wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4276407E.6030205@boost-consulting.com...
The type of the container is complicated, but you don't have to mention it anywhere because FOREACH correctly handles rvalues.
This is very powerful.
And dangerous. Cause allows developer to "forget" about an extra copy. I guess I could live with it. I wrap it into my own header and disable rvalues by definining appropriate macros
Code that returns STL containers by value is already inefficient. Why prevent FOREACH from working with such code? I don't understand. Besides, eliminating the rvalue requirement won't simplify the code because much of that machinery is needed anyway to prevent the macro args from being reevaluated. The rvalue stuff practically falls out of that. I hope that you aren't reintroducing reevaluation bugs by "defining appropriate macros".
2. Usage of Boost.Range
I understand why FOREACH is using Boost.Range, but: a) In many (most) cases I (and any other developer now) working with stl containers and wouldn't need any extra help from boost.range for FOREACH to work properly. b) Usage of Boost.Range introduces an extra dependency on ... Boost.Range and everything it depends on in its' turn (including all portability limitations). I for one couldn't afford this dependency, c) Usage of Boost.Range adding a level of indiration and slightly complicate am implementation
Actually, I switched to Boost.Range to make the implementation *less* complicated.
It adds a level of indirection, right. You are using Boost.Range for support legacy arrays and extencibility. If you would stick with col.begin() and col.end() it would be simpler.
Sure, and if we did away with FOREACH and used the for keyword, it would be simplier. And if we threw out for and used goto .... ;-) The complexity is there for a reason. Being able to iterate over arrays, strings, containers, iterator ranges is a design goal. So is providing an extensibility mechanism.
I am not going to propose to eliminate this dependency completely. But I think we need to make it optional.
What do you mean by and optional dependency on Boost.Range?
#ifndef BOOST_FOREACH_NO_BOOST_RANGE_DEPENDENCY
or
#ifndef BOOST_FOREACH_NO_EXTENCIONS
This doesn't even begin to answer my question, but maybe I should have been more specific. How would I implement the code to make the dependency on Boost.Range optional? And what sort of advice do I give people who want to extend FOREACH if the extensibility points are also optional? -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:427652AD.1020900@boost-consulting.com...
Gennadiy Rozental wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:4276407E.6030205@boost-consulting.com...
The type of the container is complicated, but you don't have to mention it anywhere because FOREACH correctly handles rvalues.
This is very powerful.
And dangerous. Cause allows developer to "forget" about an extra copy. I guess I could live with it. I wrap it into my own header and disable rvalues by definining appropriate macros
Code that returns STL containers by value is already inefficient. Why prevent FOREACH from working with such code? I don't understand.
That's good point.
Besides, eliminating the rvalue requirement won't simplify the code because much of that machinery is needed anyway to prevent the macro args from being reevaluated. The rvalue stuff practically falls out of that.
Lets see: to support rvalues you need: # include <new> # include <boost/aligned_storage.hpp> # include <boost/utility/enable_if.hpp> # include <boost/type_traits/is_array.hpp> struct rvalue_probe template<typename T> struct simple_variant cheap_copy Quite a lot actually.
I hope that you aren't reintroducing reevaluation bugs by "defining appropriate macros".
I would define BOOST_FOREACH_NO_RVALUE_DETECTION BOOST_FOREACH_NO_CONST_RVALUE_DETECTION does it reintroduce reevaluation bugs?
The complexity is there for a reason. Being able to iterate over arrays, strings, containers, iterator ranges is a design goal. So is providing an extensibility mechanism.
I see it as least important goal. IMO any container that isn't stl compartible is not worth paying attention anyway. Raw arrays I do not use (and we shouldn't encourage users). std::string should work out pf the box (is it?). Any other string (like CString) I wouldn't bother. And as for iterator ranges I would use boost::iterator_range instead of std::pair. So making it optional is worth trying I believe. On the way you could eliminate: #include <boost/range/end.hpp> #include <boost/range/begin.hpp> #include <boost/range/result_iterator.hpp> and everything it depends on.
What do you mean by and optional dependency on Boost.Range?
#ifndef BOOST_FOREACH_NO_EXTENTIONS
This doesn't even begin to answer my question, but maybe I should have been more specific. How would I implement the code to make the dependency on Boost.Range optional?
The same way you deal with other optional functionality: #ifndef BOOST_FOREACH_NO_EXTENTIONS template<typename T, typename C> inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type> begin(auto_any_t col, type2type<T, C> *, void *, boost::mpl::true_ *) { return auto_any_cast<T, C>(col).begin(); } #else template<typename T, typename C> inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type> begin(auto_any_t col, type2type<T, C> *, void *, boost::mpl::true_ *) { return foreach_detail_::adl_begin(auto_any_cast<T, C>(col)); } #endif
And what sort of advice do I give people who want to extend FOREACH if the extensibility points are also optional?
Depends on what you choose as default. If you do not define BOOST_FOREACH_NO_EXTENTIONS by default then nothing changes for those people. You just add a note that if you do not need support for extencibility one need to define BOOST_FOREACH_NO_EXTENTIONS. Or vice versa you define BOOST_FOREACH_NO_EXTENTIONS by default then those who need to extend it would need to define BOOST_FOREACH_EXTENTIONS and in you header: #ifndef BOOST_FOREACH_EXTENTIONS #define BOOST_FOREACH_NO_EXTENTIONS #endif Gennadiy

Gennadiy Rozental wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:427652AD.1020900@boost-consulting.com...
Besides, eliminating the rvalue requirement won't simplify the code because much of that machinery is needed anyway to prevent the macro args from being reevaluated. The rvalue stuff practically falls out of that.
Lets see: to support rvalues you need:
# include <new> # include <boost/aligned_storage.hpp> # include <boost/utility/enable_if.hpp> # include <boost/type_traits/is_array.hpp> struct rvalue_probe template<typename T> struct simple_variant cheap_copy
Quite a lot actually.
True, but much of this is only needed for the *const* rvalue stuff. If there were general agreement that there's fat to trim (is there?), dropping *const* rvalue support would be an easy target. Plain rvalue support is just too useful to drop, IMO. Anyway, you're the first person to complain about this dependency. Are your compile times noticeably faster when you define the no-rvalue macros? If you could post compile times with and without, that would be interesting.
I hope that you aren't reintroducing reevaluation bugs by "defining appropriate macros".
I would define BOOST_FOREACH_NO_RVALUE_DETECTION BOOST_FOREACH_NO_CONST_RVALUE_DETECTION does it reintroduce reevaluation bugs?
No, that's fine.
The complexity is there for a reason. Being able to iterate over arrays, strings, containers, iterator ranges is a design goal. So is providing an extensibility mechanism.
I see it as least important goal. IMO any container that isn't stl compartible is not worth paying attention anyway. Raw arrays I do not use (and we shouldn't encourage users).
They are quite useful in some domains.
std::string should work out pf the box (is it?).
Yes, but I was refering to native (C-style) strings, as in: BOOST_FOREACH(char ch, "hello world")
Any other string (like CString) I wouldn't bother.
The fact that BOOST_FOREACH is extensible enough to handle CString is a strong argument in its favor, IMO. And as for
iterator ranges I would use boost::iterator_range instead of std::pair. So making it optional is worth trying I believe. On the way you could eliminate: #include <boost/range/end.hpp> #include <boost/range/begin.hpp> #include <boost/range/result_iterator.hpp>
and everything it depends on.
I still don't see why this is such a concern.
How would I implement the code to make the dependency on Boost.Range optional?
The same way you deal with other optional functionality:
#ifndef BOOST_FOREACH_NO_EXTENTIONS template<typename T, typename C> inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type> begin(auto_any_t col, type2type<T, C> *, void *, boost::mpl::true_ *) { return auto_any_cast<T, C>(col).begin(); } #else template<typename T, typename C> inline auto_any<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type> begin(auto_any_t col, type2type<T, C> *, void *, boost::mpl::true_ *) { return foreach_detail_::adl_begin(auto_any_cast<T, C>(col)); } #endif
This would effectively double the amount of code in foreach.hpp, and double the test matrix. I would need to see some hard numbers about compile times before I do that. -- Eric Niebler Boost Consulting www.boost-consulting.com

#include <boost/range/end.hpp> #include <boost/range/begin.hpp> #include <boost/range/result_iterator.hpp>
and everything it depends on.
I still don't see why this is such a concern.
My primary concern as a Boost.Test developer who want to employ FOREACH is portability. And simpler/less depencencies the code is/has the easier to achive a portability I need. And a secondary point is that IMO 95 % of users will only need this basic support. So why should they pay for something that only 5 percent of users need.
This would effectively double the amount of code in foreach.hpp, and
I do not think that's true. Essentially you only need an alternative implementation for begin and end.
double the test matrix. I would need to see some hard numbers about compile times before I do that.
It's would be just another level of compatibility: stl compatible containers only. Gennadiy

Gennadiy Rozental wrote:
#include <boost/range/end.hpp> #include <boost/range/begin.hpp> #include <boost/range/result_iterator.hpp>
and everything it depends on.
I still don't see why this is such a concern.
My primary concern as a Boost.Test developer who want to employ FOREACH is portability. And simpler/less depencencies the code is/has the easier to achive a portability I need.
I would first try to improve the portability of BOOST_FOREACH without cutting features. As a side-effect, we may end up improving the portability of Boost.Range in the process, and that's a Good Thing. Are there platforms for which FOREACH can be made to work but for which Boost.Range cannot? If that's the case, then you may have a point. But even then, if it turns out that I must duplicate much of the Boost.Range machinery (and all its broken compiler work-arounds) just to satisfy one broken, legacy compiler, it may not be worth it.
And a secondary point is that IMO 95 % of users will only need this basic support. So why should they pay for something that only 5 percent of users need.
These numbers are speculative. It's hard to judge how people are using FOREACH. In the absence of usage data, I prefer a library with broad applicability/extensibility.
This would effectively double the amount of code in foreach.hpp, and
I do not think that's true. Essentially you only need an alternative implementation for begin and end.
True. But there are 2 implementations for begin/end already to deal with compilers that can't handle const rvalues. Seems that Boost.Range-independence axis is orthogonal to the const-rvalue axis, so I would need 4 variants each of begin and end. Yuk.
double the test matrix. I would need to see some hard numbers about compile times before I do that.
It's would be just another level of compatibility: stl compatible containers only.
It's an alternate code path. As such, it would need to be tested and maintained. (I still think some hard data about compile times would help guide this discussion.) -- Eric Niebler Boost Consulting www.boost-consulting.com

This would effectively double the amount of code in foreach.hpp, and
I do not think that's true. Essentially you only need an alternative implementation for begin and end.
True. But there are 2 implementations for begin/end already to deal with compilers that can't handle const rvalues. Seems that Boost.Range-independence axis is orthogonal to the const-rvalue axis, so I would need 4 variants each of begin and end. Yuk.
I don't think having stl only containers with rvalues support is necessary. After all you want simplest version - you get it. Gennadiy P.S. as for compilation time overhead, it's difficult to get any reliable quantative data. It depends on too many factors including the complexity of the code by itself, compiler, debug/release mode and how heavy FOREACH is used.

"Eric Niebler" <eric@boost-consulting.com> writes:
Gennadiy Rozental wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:427652AD.1020900@boost-consulting.com...
Besides, eliminating the rvalue requirement won't simplify the code because much of that machinery is needed anyway to prevent the macro args from being reevaluated. The rvalue stuff practically falls out of that. Lets see: to support rvalues you need: # include <new> # include <boost/aligned_storage.hpp> # include <boost/utility/enable_if.hpp> # include <boost/type_traits/is_array.hpp> struct rvalue_probe template<typename T> struct simple_variant cheap_copy Quite a lot actually.
True, but much of this is only needed for the *const* rvalue stuff. If there were general agreement that there's fat to trim (is there?), dropping *const* rvalue support would be an easy target.
Don't do it! I plan to write some functions that return const rvalues. Plus, Scott Meyers recommends it, so you'll encounter it. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Eric Niebler" <eric@boost-consulting.com> writes:
True, but much of this is only needed for the *const* rvalue stuff. If there were general agreement that there's fat to trim (is there?), dropping *const* rvalue support would be an easy target.
Don't do it! I plan to write some functions that return const rvalues. Plus, Scott Meyers recommends it, so you'll encounter it.
Const rvalues aren't movable, though. :-)

"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
"Eric Niebler" <eric@boost-consulting.com> writes:
True, but much of this is only needed for the *const* rvalue stuff. If there were general agreement that there's fat to trim (is there?), dropping *const* rvalue support would be an easy target. Don't do it! I plan to write some functions that return const rvalues. Plus, Scott Meyers recommends it, so you'll encounter it.
Const rvalues aren't movable, though. :-)
I think you could make them move, couldn't you? Anyway, these const rvalues are views and proxies, so you can't gain anything by moving: it would be the same as copying. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d55g76$sn0$1@sea.gmane.org... | Hopefully soon enough we may be able to write | | auto const& r = v | filter(my_pred()) | transform(my_func()); | | BOOST_FOREACH(..., r ) { | } hopefully we soon will be able to say for( ... : v | std::filter(my_pred()) | std::transform(my_func()) ) { ... } but it is still years away. -Thorsten

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
This is very powerful.
And dangerous. Cause allows developer to "forget" about an extra copy.
I'm not sure where you think the "extra" copy is. The copy is already implicit in the RHS expression, isn't it? In general C++ will make lots of copies you can't control. Extra copies are hardly "dangerous" (except maybe with auto_ptr). They may be inefficient, but then I don't believe in trying to prevent people from writing inefficient code, especially when that's more convenient. Very little of the code end users write actually needs to be fast. -- Dave Abrahams Boost Consulting www.boost-consulting.com

And dangerous. Cause allows developer to "forget" about an extra copy.
I'm not sure where you think the "extra" copy is. The copy is already implicit in the RHS expression, isn't it?
No. In this case we could control the copy. collection foo(); returns temporary. FOREACH make copy of this temporary into another temporary. This is an extra copy. Which we could easily control/eliminate with collection const& c = foo(); statement.
In general C++ will make lots of copies you can't control. Extra copies are hardly "dangerous" (except maybe with auto_ptr). They may be inefficient, but then I don't believe in trying to prevent people from writing inefficient code, especially when that's more convenient. Very little of the code end users write actually needs to be fast.
That's true. But danger in this case caused by the fact that FOREACH make an extra copy silently. Ok. I agree to keep this functionality. But there should be a bug disclaimer about this overhead. Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
And dangerous. Cause allows developer to "forget" about an extra copy.
I'm not sure where you think the "extra" copy is. The copy is already implicit in the RHS expression, isn't it?
No. In this case we could control the copy.
collection foo();
returns temporary. FOREACH make copy of this temporary into another temporary.
Are you sure that copy can't be elided?
This is an extra copy. Which we could easily control/eliminate with
collection const& c = foo();
statement.
In general C++ will make lots of copies you can't control. Extra copies are hardly "dangerous" (except maybe with auto_ptr). They may be inefficient, but then I don't believe in trying to prevent people from writing inefficient code, especially when that's more convenient. Very little of the code end users write actually needs to be fast.
That's true. But danger in this case caused by the fact that FOREACH make an extra copy silently.
Not danger; inefficiency.
Ok. I agree to keep this functionality. But there should be a bug disclaimer about this overhead.
Not bug... I don't know what. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> writes:
returns temporary. FOREACH make copy of this temporary into another temporary.
Are you sure that copy can't be elided?
I do not know. FOREACH makes copy from temporary into simple variant using placement new.
Hm, unlikely. Oh well, there's always move semantics ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote
bool first = true; BOOST_FOREACH(....) { if(first) { do_something(); first = false; } }
Wanting the last element is very nearly as common as wanting the first. Putting this after the loop requires an extra check for an empty container. Why do you not wish to expose the iterator in BOOST_FOR_EACH ? regards Andy Little

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d53uss$p3n$1@sea.gmane.org... | 1. Rvalues support | I agree it's cool and "magical" - the way you added support for rvalues. But | I believe it's actually misplaced efforts. IMO support for rvalues brings | more harm than advantage. I could accidently or mindlessly (using some | global replacement in sources, for example) introduce rvalue in | BOOST_FOREACH statement and compiler wouldn't warn me. Now I am paying for | an unnessesary copying. while exist perfectly good alternative that doesn't | require it: | | my_collection_type my_function(); | ... | | my_collection_type const& v = my_function() | | BOOST_FOREACH(... , v ) | { | } | | In addition eliminating rvalues support will signicantly simplify | implementation and as a result speed up compilation. hm...that won't save you anything AFAICT. | 2. Usage of Boost.Range | | I understand why FOREACH is using Boost.Range, but: | a) In many (most) cases I (and any other developer now) working with stl | containers and wouldn't need any extra help from boost.range for FOREACH to | work properly. things like pair<iterator,iterator> are very common...just look at BGL. besides, you need a way to make your own collection work with foreach. | b) Usage of Boost.Range introduces an extra dependency on ... Boost.Range | and everything it depends on in its' turn (including all portability | limitations). I for one couldn't afford this dependency, | c) Usage of Boost.Range adding a level of indiration and slightly | complicate am implementation so.? the standard containers part of it is pretty portable. -Thorsten

| In addition eliminating rvalues support will signicantly simplify | implementation and as a result speed up compilation.
hm...that won't save you anything AFAICT.
Why, It saves me rvalue detection and suuport logic. I do not need one now: now parcing, now template instanciations
| 2. Usage of Boost.Range | | I understand why FOREACH is using Boost.Range, but: | a) In many (most) cases I (and any other developer now) working with stl | containers and wouldn't need any extra help from boost.range for FOREACH to | work properly.
things like pair<iterator,iterator> are very common...just look at BGL.
besides, you need a way to make your own collection work with foreach.
Not in my development. Anyway I do not propose to eliminate it completely. Just provide the way to disable this.
| b) Usage of Boost.Range introduces an extra dependency on ... Boost.Range | and everything it depends on in its' turn (including all portability | limitations). I for one couldn't afford this dependency, | c) Usage of Boost.Range adding a level of indiration and slightly | complicate am implementation
so.? the standard containers part of it is pretty portable.
Try to compile with all compilers we support. In some cases It just fails somewhere within Boost.Range headers. Also why would I need to include all there headers if I am not really need them. Gennadiy

"Gennadiy Rozental" <gennadiy.rozental@thomson.com> wrote in message news:d55hn9$4c5$1@sea.gmane.org... |> | In addition eliminating rvalues support will signicantly simplify | > | implementation and as a result speed up compilation. | > | > hm...that won't save you anything AFAICT. | | Why, It saves me rvalue detection and suuport logic. I do not need one now: | now parcing, now template instanciations yes, it might slow down compilation, so what? | > | 2. Usage of Boost.Range | > | | > | I understand why FOREACH is using Boost.Range, but: | > | a) In many (most) cases I (and any other developer now) working with stl | > | containers and wouldn't need any extra help from boost.range for FOREACH | > to | > | work properly. | > | > things like pair<iterator,iterator> are very common...just look at BGL. | > | > besides, you need a way to make your own collection work with foreach. | | Not in my development. Anyway I do not propose to eliminate it completely. | Just provide the way to disable this. ok. | > | b) Usage of Boost.Range introduces an extra dependency on ... | > Boost.Range | > | and everything it depends on in its' turn (including all portability | > | limitations). I for one couldn't afford this dependency, | > | c) Usage of Boost.Range adding a level of indiration and slightly | > | complicate am implementation | > | > so.? the standard containers part of it is pretty portable. | | Try to compile with all compilers we support. In some cases It just fails | somewhere within Boost.Range headers. Also why would I need to include all | there headers if I am not really need them. maybe you should put some effort into making those compilers work? -Thorsten

yes, it might slow down compilation, so what?
Well. It's attitude/practice issue. In my practice I may compile twice a minute so compilation time does matter.
maybe you should put some effort into making those compilers work?
Isn't this self directed? ;)) Or you porpose to fix a compilers? Gennadiy

Gennadiy Rozental wrote:
Try to compile with all compilers we support. In some cases It just fails somewhere within Boost.Range headers. Also why would I need to include all there headers if I am not really need them.
I did a quick release build test using bcc32 5.6.4 and iterating over a list<int> using a simple for loop and BOOST_FOREACH showed that BOOST_FOREACH generates nearly twice as many instructions as using the hand-written for loop. Borland's optimiser isn't great, so I guess that is part of the problem. Cheers Russell
participants (36)
-
Andrei Alexandrescu (See Website For Email)
-
Andy Little
-
Angus Leeming
-
Arkadiy Vertleyb
-
Beman Dawes
-
Daniel Wallin
-
Darren Cook
-
David Abrahams
-
David Brownell
-
Edward Diener
-
Eric Niebler
-
Gennadiy Rozental
-
Giovanni Bajo
-
Giovanni P. Deretta
-
Hartmut Kaiser
-
Iain K. Hanson
-
Iain K. Hanson
-
jarvi
-
Jeff Flinn
-
Joe Gottman
-
Joel
-
Joel de Guzman
-
Jonathan Turkanis
-
Martin
-
Matt Hurd
-
michael toksvig
-
Nicolas Lelong
-
Paul A Bristow
-
Paul Mensonides
-
Pavel Vozenilek
-
Peter Dimov
-
Robert Ramey
-
Russell Hind
-
Stefan Seefeld
-
Stefan Strasser
-
Thorsten Ottosen