BOOST_FOREACH questions

Eric, I've some questions about BOOST_FOREACH (which is pretty cool, BTW). 1. Is it possible to use typeof on gcc, to avoid any possible overhead? While you've posted some results which show that gcc generally can optimise it very well, I'd like to be 100% sure). Something like: #define FOR_EACH(var, container) \ for(typeof(container.begin()) _for_each_i = container.begin(),\ _for_each_e = container.end();\ _for_each_i != _for_each_e; ++_for_each_i)\ if(bool _for_each_continue = false) {}\ else\ for(var = *_for_each_i; !_for_each_continue; _for_each_continue=true) which works perfectly for me. 2. Any chance that BOOST_FOREACH((pair<int, int> p), container) will work? I don't know how to make it work without require paranthethis in all cases, but maybe there's a smart trick. 3. Is it possible that you place this to sandbox, for easier access? - Volodya

Vladimir Prus <ghost@cs.msu.su> writes:
Eric, I've some questions about BOOST_FOREACH (which is pretty cool, BTW).
FYI, Eric is sort of on vacation for another week or so. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Vladimir Prus wrote:
Eric, I've some questions about BOOST_FOREACH (which is pretty cool, BTW).
Thanks!
1. Is it possible to use typeof on gcc, to avoid any possible overhead? While you've posted some results which show that gcc generally can optimise it very well, I'd like to be 100% sure). Something like:
#define FOR_EACH(var, container) \ for(typeof(container.begin()) _for_each_i = container.begin(),\ _for_each_e = container.end();\ _for_each_i != _for_each_e; ++_for_each_i)\ if(bool _for_each_continue = false) {}\ else\ for(var = *_for_each_i; !_for_each_continue; _for_each_continue=true)
which works perfectly for me.
It's probably possible, but there are a couple of subtle issues that would need to be dealt with. First, BOOST_FOREACH should be extensible, meaning, there should be a well-defined way to "hook" BOOST_FOREACH to get it to enumerate other user-defined collections. The mechanism to hook BOOST_FOREACH should be the same regardless of whether BOOST_FOREACH is implemented with native typeof or not. Second, BOOST_FOREACH should work out of the box with arrays, null-terminated strings and iterator pairs in addition to STL(-like) containers. The second should be easy, but the first would require some careful design. Considering that BOOST_FOREACH is pretty optimal already, I'm not convinced it's worth it. Also, note that the above version is buggy because it doesn't handle break statements correctly.
2. Any chance that
BOOST_FOREACH((pair<int, int> p), container)
will work? I don't know how to make it work without require paranthethis in all cases, but maybe there's a smart trick.
I don't think so, sorry. You would have to use a typedef, as in: typedef pair<int,int> pair_int; BOOST_FOREACH( pair_int p, container )
3. Is it possible that you place this to sandbox, for easier access?
Done. It's at boost-sandbox/boost/foreach.hpp. You'll notice that it's a reimplementation. This version only evaluates the container expression once, so you can use complicated expressions as the second parameter. This makes BOOST_FOREACH very useful with filtered ranges, where the element type is simple, but the type of the "container" is very complicated. I'll probably need some docs and tests at some point. It's really quite useful and safe now(*) so perhaps I'll actually put it up for review soon. (*) There is one outstanding problem that I have not yet solved. I think it's unsolvable in the current language, but I hope I'm wrong. The current implementation does the wrong thing when the container expression is a const-qualified rvalue STL container. It uses the rules for binding to reference to distinguish lvalues from rvalues, storing references for lvalues and copies for rvalues. Const-qualified rvalues screw this up, so the following crashes: std::vector<int> const get_vector(); ... BOOST_FOREACH( int i, get_vector() ) I'm not sure how serious this problem is. If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote:
I'll probably need some docs and tests at some point. It's really quite useful and safe now(*) so perhaps I'll actually put it up for review soon.
(*) There is one outstanding problem that I have not yet solved. I think it's unsolvable in the current language, but I hope I'm wrong. The current implementation does the wrong thing when the container expression is a const-qualified rvalue STL container. It uses the rules for binding to reference to distinguish lvalues from rvalues, storing references for lvalues and copies for rvalues. Const-qualified rvalues screw this up, so the following crashes:
std::vector<int> const get_vector(); ... BOOST_FOREACH( int i, get_vector() )
I'm not sure how serious this problem is. If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears.
Oddly enough, I was thinking about this last night, and wrote the attached code. It may be wildly wrong, both because I haven't give it much thought and because I am not an expert in this area of the language. In particular, I may have left out key use cases, or misclassified some cases. It passes on VC7.1, Comeau 4.3.3 and GCC 3.4.1, and passes all but one test on Intel 8.0. Jonathan P.S. One problem I just noticed is that is passes non-POD types through ellipses. I tried using the any_conversion technique from is_convertible, but it didn't work. Maybe someone can fix it. begin 666 is_lvalue.cpp M(VEN8VQU9&4@/'-T<FEN9SX-"B-I;F-L=61E(#QB;V]S="]U=&EL:71Y+V5N M86)L95]I9BYH<' ^#0HC:6YC;'5D92 \8F]O<W0O<W1A=&EC7V%S<V5R="YH M<' ^#0HC:6YC;'5D92 \8F]O<W0O='EP95]T<F%I=',O:7-?8V]N<W0N:'!P M/@T*(VEN8VQU9&4@/&)O;W-T+W1Y<&5?=')A:71S+V1E=&%I;"]Y97-?;F]? M='EP92YH<' ^#0H-"FYA;65S<&%C92!B;V]S="![(&YA;65S<&%C92!D971A M:6P@>PT*#0IT96UP;&%T93QT>7!E;F%M92!4/@T*='EP95]T<F%I=',Z.GEE M<U]T>7!E(&QV86QU95]T97-T,2A4)BD[#0H-"G1E;7!L871E/'1Y<&5N86UE M(%0^#0IT>7!E7W1R86ET<SHZ;F]?='EP92!L=F%L=65?=&5S=#$H8V]N<W0@ M5"8I.PT*#0IT>7!E7W1R86ET<SHZ;F]?='EP92!L=F%L=65?=&5S=#(H+BXN M*3L-"@T*=&5M<&QA=&4\='EP96YA;64@5#X-"G1Y<&5?=')A:71S.CIY97-? M='EP92 -"FQV86QU95]T97-T,B@@5"8L( T*(" @(" @(" @(" @("!T>7!E M;F%M92 -"B @(" @(" @(" @(" @96YA8FQE7VEF/ T*(" @(" @(" @(" @ M(" @(" @:7-?8V]N<W0\5#X-"B @(" @(" @(" @(" @/CHZ='EP92H@/2 P M("D[#0H-"GT@?2 O+R!N86UE<W!A8V4N#0H-"B-D969I;F4@0D]/4U1?25-? M3%9!3%5%*'@I(%P-"B @(" H('-I>F5O9BAB;V]S=#HZ9&5T86EL.CIL=F%L M=65?=&5S=#$H>"DI(#T](%P-"B @(" @('-I>F5O9BAB;V]S=#HZ='EP95]T M<F%I=',Z.GEE<U]T>7!E*2 I('Q\(%P-"B @(" H('-I>F5O9BAB;V]S=#HZ M9&5T86EL.CIL=F%L=65?=&5S=#(H>"DI(#T](%P-"B @(" @('-I>F5O9BAB M;V]S=#HZ='EP95]T<F%I=',Z.GEE<U]T>7!E*2 I(%P-"B @(" O*BHO#0H- M"FEN="!F*"D@>R!R971U<FX@,#L@?0T*#0IS=&0Z.G-T<FEN9R!G*"D@>R!R M971U<FX@(FAE;&QO(CL@?0T*8V]N<W0@<W1D.CIS=')I;F<@:"@I('L@<F5T M=7)N(")H96QL;R([('T-"@T*:6YT(&UA:6XH*0T*>R @( T*(" @(&EN="!I M,3L-"B @("!C;VYS="!I;G0@:3(@/2 P.PT*(" @('-T9#HZ<W1R:6YG(',Q M.PT*(" @(&-O;G-T('-T9#HZ<W1R:6YG(',R(#T@(FAE;&QO(CL-"B @("!" M3T]35%]35$%424-?05-315)4*$)/3U-47TE37TQ604Q512AI,2DI.PT*(" @ M($)/3U-47U-4051)0U]!4U-%4E0H0D]/4U1?25-?3%9!3%5%*&DR*2D[#0H@ M(" @0D]/4U1?4U1!5$E#7T%34T525"A"3T]35%])4U],5D%,544H<S$I*3L- M"B @("!"3T]35%]35$%424-?05-315)4*$)/3U-47TE37TQ604Q512AS,BDI M.PT*(" @($)/3U-47U-4051)0U]!4U-%4E0H(4)/3U-47TE37TQ604Q512AF M*"DI*3L-"B @("!"3T]35%]35$%424-?05-315)4*"%"3T]35%])4U],5D%, M544H9R@I*2D[#0H@(" @0D]/4U1?4U1!5$E#7T%34T525"@A0D]/4U1?25-? M3%9!3%5%*&@H*2DI.PT*(" @($)/3U-47U-4051)0U]!4U-%4E0H(4)/3U-4 87TE37TQ604Q512@B:&5L;&\B*2D[#0I] ` end

Jonathan Turkanis wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote:
If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears.
Oddly enough, I was thinking about this last night, and wrote the attached code. It may be wildly wrong <snip>
Unfortunately, it is. There is a precedence problem because the expression to which the macro expands is not enclosed in parens. In your tests, the ! is only applied to part of the expression, leading to false positives. Keep trying though. :-) -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:41AE786B.50306@boost-consulting.com...
Jonathan Turkanis wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote:
If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears.
Oddly enough, I was thinking about this last night, and wrote the attached
code.
It may be wildly wrong <snip>
Unfortunately, it is. There is a precedence problem because the expression to which the macro expands is not enclosed in parens. \
Whoops! I can't believe I made that mistake.
In your tests, the ! is only applied to part of the expression, leading to false positives.
I think it leads to true negatives. ;-) The case you're interested in is const std::string h() { return "hello"; } BOOST_STATIC_ASSERT(!BOOST_IS_LVALUE(h())); which now fails, except on GCC 3.4 :( Are you sure GCC is wrong here? Jonathan

Jonathan Turkanis wrote:
The case you're interested in is
const std::string h() { return "hello"; } BOOST_STATIC_ASSERT(!BOOST_IS_LVALUE(h()));
which now fails, except on GCC 3.4 :( Are you sure GCC is wrong here?
Not 100% sure, but I'm inclined to think so. The reason is the second overload of lvalue_test2: template<typename T> type_traits::yes_type lvalue_test2( T&, int, typename enable_if< is_const<T> >::type* = 0 ); Given an expression of type "const rvalue-type", the expression will successfully bind to the T& with T deduced as "const rvalue-type". Then, enable_if< is_const<T> > will succeed, so this overload is chosen over the one with the elipses. That's causing the false positive (true negative). Seems to me that Arkadiy has run up against the same problem with BOOST_TYPEOF_PRESERVE_LVALUE, which also gets this case wrong (according to the docs). -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in:
Seems to me that Arkadiy has run up against the same problem with BOOST_TYPEOF_PRESERVE_LVALUE, which also gets this case wrong (according to the docs).
Yeah, that's what I was thinking about last night. I was trying to see how close I could approximate decltype. Jonathan

Jonathan Turkanis wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in:
Seems to me that Arkadiy has run up against the same problem with BOOST_TYPEOF_PRESERVE_LVALUE, which also gets this case wrong (according to the docs).
Yeah, that's what I was thinking about last night. I was trying to see how close I could approximate decltype.
Here is an interesting way to "distinguish" between L-values and R-values. The following program uses the properties of the conditional operator to implement an IS_LVALUE macro that detects the value-ness of an expression and prints its determination. It works with gcc 3.3.3 and with Comeau online, but vc7.1 doesn't like it. Alas, I haven't yet figured out a way to use this technique to get a compile-time constant. Maybe someone more clever than myself can figure that out. #include <stdio.h> struct foo { template<typename U> operator U () const { throw "R-value"; } template<typename V> operator V & () volatile const { throw "L-value"; } }; foo const f = {}; #define IS_LVALUE(x) \ try { (true? f : (x)); } \ catch( char const *value ) { printf("%s\n",value); } struct bar {}; bar baz1() { static bar b; return b; } bar const baz2() { static bar b; return b; } bar & baz3() { static bar b; return b; } bar const & baz4() { static bar b; return b; } int main() { bar b; bar const cb = {}; // l-values IS_LVALUE(b); IS_LVALUE(cb); // r-values IS_LVALUE(baz1()); IS_LVALUE(baz2()); // l-values IS_LVALUE(baz3()); IS_LVALUE(baz4()); return 0; } -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Jonathan Turkanis wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in:
Seems to me that Arkadiy has run up against the same problem with BOOST_TYPEOF_PRESERVE_LVALUE, which also gets this case wrong (according to the docs).
Yeah, that's what I was thinking about last night. I was trying to see how close I could approximate decltype.
Here is an interesting way to "distinguish" between L-values and R-values. The following program uses the properties of the conditional operator to implement an IS_LVALUE macro that detects the value-ness of an expression and prints its determination. It works with gcc 3.3.3 and with Comeau online, but vc7.1 doesn't like it. Alas, I haven't yet figured out a way to use this technique to get a compile-time constant.
#include <boost/static_assert.hpp> typedef char yes; typedef char (&no)[2]; template <class T> yes is_nonconst_rvalue(T const&, ...); template <class T> no is_nonconst_rvalue(T&, int); struct foo { template<typename U> operator U () const; template<typename V> operator V & () volatile const; static foo const instance; static bool select; }; #define IS_RVALUE(x) \ (sizeof(is_nonconst_rvalue((foo::select ? foo::instance : (x)), 0)) == sizeof(yes)) int rvalue(); int const_rvalue(); int& lvalue(); int const& const_lvalue(); BOOST_STATIC_ASSERT(IS_RVALUE(rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_lvalue())); Still no dice for vc7.1, though. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Still no dice for vc7.1, though.
Hum, that was too easy: #include <boost/static_assert.hpp> typedef char yes; typedef char (&no)[2]; template <class T> yes is_nonconst_rvalue(T const&, ...); template <class T> no is_nonconst_rvalue(T&, int); struct foo { #ifndef BOOST_MSVC template<typename U> operator U() const; template<typename V> operator V& () volatile const ; #else template<typename U> operator U() volatile; template<typename V> operator V& () const ; #endif static foo const instance; static bool select; }; #define IS_RVALUE(x) \ (sizeof(is_nonconst_rvalue((foo::select ? foo::instance : (x)), 0)) == sizeof(yes)) int rvalue(); int const_rvalue(); int& lvalue(); int const& const_lvalue(); int volatile volatile_rvalue(); int const_volatile_rvalue(); int volatile& volatile_lvalue(); int const volatile& const_volatile_lvalue(); BOOST_STATIC_ASSERT(IS_RVALUE(rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_lvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(volatile_rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_volatile_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(volatile_lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_volatile_lvalue())); -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
David Abrahams wrote:
Still no dice for vc7.1, though.
Hum, that was too easy:
Well, there are still some unhandled corner cases. Maybe someone more clever than I can figure out how to manage them. I'm thinking these may require the Rani Sharoni trick from is_base_and_derived, but since I don't really understand it, I'll admit I'm just speculating. I doubt there's a cure for the one vc7.1 failure, but I could of course be wrong. The other failures I'm labelling as "corner cases" because they only fail on oddball cases like "(volatile x)x()" or rvalue expressions with private copy ctors, or ones that can't be evaluated anyway. If there's no copy ctor that takes an "x volatile" argument, you can't return one from a function. #include <boost/static_assert.hpp> typedef char yes; typedef char (&no)[2]; template <class T> yes is_nonconst_rvalue(T const&, ...); template <class T> no is_nonconst_rvalue(T&, int); struct foo { #ifndef BOOST_MSVC template<typename U> operator U() const; template<typename V> operator V& () volatile const; #else template<typename U> operator U(); template<typename V> operator V& () const volatile; #endif static foo const instance; static bool select; }; #define IS_RVALUE(x) \ (sizeof(is_nonconst_rvalue((foo::select ? foo::instance : (x)), 0)) == sizeof(yes)) int rvalue(); int const_rvalue(); int& lvalue(); int const& const_lvalue(); int volatile volatile_rvalue(); int const volatile const_volatile_rvalue(); int volatile& volatile_lvalue(); int const volatile& const_volatile_lvalue(); BOOST_STATIC_ASSERT(IS_RVALUE(rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_lvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(volatile_rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_volatile_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(volatile_lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_volatile_lvalue())); struct x { ~x(); }; x rvaluex(); x const_rvaluex(); x& lvaluex(); x const& const_lvaluex(); x volatile volatile_rvaluex(); x const volatile const_volatile_rvaluex(); x volatile& volatile_lvaluex(); x const volatile& const_volatile_lvaluex(); BOOST_STATIC_ASSERT(IS_RVALUE(rvaluex())); BOOST_STATIC_ASSERT(IS_RVALUE(const_rvaluex())); BOOST_STATIC_ASSERT(!IS_RVALUE(lvaluex())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_lvaluex())); // foo.cpp:76: error: No match for 'x(volatile x)' // foo.cpp:59: error: candidates are: x::x() // foo.cpp:59: error: x::x(const x &) BOOST_STATIC_ASSERT(IS_RVALUE(volatile_rvaluex())); // foo.cpp:77: error: No match for 'x(const volatile x)' // foo.cpp:59: error: candidates are: x::x() // foo.cpp:59: error: x::x(const x &) BOOST_STATIC_ASSERT(IS_RVALUE(const_volatile_rvaluex())); BOOST_STATIC_ASSERT(IS_RVALUE((volatile x)x())); BOOST_STATIC_ASSERT(!IS_RVALUE(volatile_lvaluex())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_volatile_lvaluex())); -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
David Abrahams wrote:
Still no dice for vc7.1, though.
Hum, that was too easy:
For every difficult problem, there is a solution that is simple, elegant ... and wrong. Correct version below fails. :( You can't use int for this test because the "const" is ignored in "int const const_rvalue()". You need to use UDTs. #include <boost/static_assert.hpp> typedef char yes; typedef char (&no)[2]; template <class T> yes is_nonconst_rvalue(T const&, ...); template <class T> no is_nonconst_rvalue(T&, int); struct foo { #ifndef BOOST_MSVC template<typename U> operator U() const; template<typename V> operator V& () volatile const; #else template<typename U> operator U() volatile; template<typename V> operator V& () const; #endif static foo const instance; static bool select; }; #define IS_RVALUE(x) \ (sizeof(is_nonconst_rvalue((foo::select ? foo::instance : (x)), 0)) == sizeof(yes)) struct bar {}; bar rvalue(); bar const const_rvalue(); bar& lvalue(); bar const& const_lvalue(); bar volatile volatile_rvalue(); bar const volatile const_volatile_rvalue(); bar volatile& volatile_lvalue(); bar const volatile& const_volatile_lvalue(); BOOST_STATIC_ASSERT(IS_RVALUE(rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_lvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(volatile_rvalue())); BOOST_STATIC_ASSERT(IS_RVALUE(const_volatile_rvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(volatile_lvalue())); BOOST_STATIC_ASSERT(!IS_RVALUE(const_volatile_lvalue())); -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
David Abrahams wrote:
David Abrahams wrote:
Still no dice for vc7.1, though.
Hum, that was too easy:
For every difficult problem, there is a solution that is simple, elegant .... and wrong. Correct version below fails. :( You can't use int for this test because the "const" is ignored in "int const const_rvalue()". You need to use UDTs.
You must've missed my more recent posting which tests UDTs. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Eric Niebler wrote:
You need to use UDTs.
You must've missed my more recent posting which tests UDTs.
That posting is buggy as well. The functions: int const_rvalue(); x const_rvaluex(); should be: int const const_rvalue(); x const const_rvaluex(); You're not testing the most interesting case! After this change, the following assert fails: BOOST_STATIC_ASSERT(IS_RVALUE(const_rvaluex())); And we're back to square 1. :( -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
David Abrahams wrote:
Eric Niebler wrote:
You need to use UDTs.
You must've missed my more recent posting which tests UDTs.
That posting is buggy as well. The functions:
int const_rvalue(); x const_rvaluex();
should be:
int const const_rvalue(); x const const_rvaluex();
You're not testing the most interesting case! After this change, the following assert fails:
BOOST_STATIC_ASSERT(IS_RVALUE(const_rvaluex()));
And we're back to square 1. :(
You're right. Sorry for wasting everyone's time. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:41AEFA46.4030305@boost-consulting.com...
Jonathan Turkanis wrote:
Yeah, that's what I was thinking about last night. I was trying to see how close I could approximate decltype.
Here is an interesting way to "distinguish" between L-values and R-values. The following program uses the properties of the conditional operator to implement an IS_LVALUE macro that detects the value-ness of an expression and prints its determination.
I thought of using the conditional operator as I was lying in bed last night. I was going to try it this morning ;-) Jonathan

Jonathan Turkanis wrote:
"Eric Niebler" <eric@boost-consulting.com> wrote in message news:41AEFA46.4030305@boost-consulting.com...
Jonathan Turkanis wrote:
Yeah, that's what I was thinking about last night. I was trying to see how
close
I could approximate decltype.
Here is an interesting way to "distinguish" between L-values and R-values. The following program uses the properties of the conditional operator to implement an IS_LVALUE macro that detects the value-ness of an expression and prints its determination.
I thought of using the conditional operator as I was lying in bed last night. I was going to try it this morning ;-)
Same here. Reminded me of the type deduction stuff in Phoenix-2 where lazy versions of c?e:t does the right thing on lvalues. Dave beat us to the punch! ;-) -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Eric Niebler wrote:
Here is an interesting way to "distinguish" between L-values and R-values.
<snip> I just committed to boost-sandbox an experimental new version of BOOST_FOREACH that uses the technique I described to correctly handle even const rvalue container expressions. I was unable to find a way to detect const r-value expressions at compile-time, so instead I use a runtime check along with boost::variant. It's fully inlineable, so the runtime check should be optimized away, although the use of variant will incur a small perf hit (not yet measured). The r-value detection stuff is rather subtle, and it requires a very compliant compiler. (In fact, I haven't yet convinced myself it's entirely kosher.) It works on gcc 3.3.3, but not on VC++, so the word to the wise is: don't use BOOST_FOREACH with const r-value container expressions on VC++. No doubt there are other compilers which are also broken with regard to the const r-value detection stuff. If anybody is interested, grab the code and try it with your favorite compiler and let me know how it works out. If it doesn't compile, try #defining BOOST_FOREACH_NO_CONST_RVALUE_DETECTION and see if that fixes the problem. It lives in boost-sandbox at ROOT/boost/foreach.hpp. I'm also attaching it here along with a simple driver. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote in message news:41B2BE9E.7000106@boost-consulting.com...
If anybody is interested, grab the code and try it with your favorite compiler and let me know how it works out. If it doesn't compile, try #defining BOOST_FOREACH_NO_CONST_RVALUE_DETECTION and see if that fixes the problem.
Here are some results (the line numbers don't match your source because I pasted the code into a test file, but the output should still be clear) - VC8.0 (beta) crashes without BOOST_FOREACH_NO_CONST_RVALUE_DETECTION defined - Comeau 4.3.3 gives two warning and an internal error regardless of whether the defect macro is defined (see end off message) - Intel 8.0 gives lots of warnings and an internal error without the defect macro, but works fine with the defect macro defined (see end off message) Jonathan ---------------------------------------------------------------- Comeau 4.3.3 compiler output with or without defect macro "C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp", line 544: warning: use of "=" where "==" may have been intended BOOST_FOREACH( T const &t, list_of_T ) ^ "C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp", line 559: warning: use of "=" where "==" may have been intended BOOST_FOREACH( int &i, int_list ) ^ "C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp", line 569: internal err or: assertion failed: add_to_destructions_list: object lifetime and dynamic init in different memory regions (il.c, line 12018) BOOST_FOREACH( int const &i, list<int>(5,5) ) ^ ---------------------------------------------- Intel 8.0 compiler output without defect macro: C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(559): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int &i, int_list ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(569): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int const &i, list<int>(5,5) ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(142): error: function ret urning array is not allowed operator U () ^ detected during instantiation of "boost::for_each::rvalue_probe::opera tor T" based on template argument <int [3]> at line 577 C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(577): internal error: ass ertion failed at: "shared/edgcpfe/exprutil.c", line 8947 BOOST_FOREACH( int &i, int_array ) ^ compilation aborted for C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp ( code 4) ---------------------------------------------- Intel 8.0 compiler output with defect macro: C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(559): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int &i, int_list ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(569): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int const &i, list<int>(5,5) ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(577): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int &i, int_array ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(583): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int i, int_array ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(592): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( char &ch, str ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(599): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( char ch, str ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(610): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( char const &ch, sz ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(621): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int &i, ::boost::for_each::in_range( begin, end ) ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(629): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int i, iter_pair ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(636): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int i, rvalue_list() ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(644): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( int i, const_rvalue_list() ) ^ C:\DOCUME~1\turkanis\Home\C++\overloadvc71\example.cpp(544): warning #187: use o f "=" where "==" may have been intended BOOST_FOREACH( T const &t, list_of_T ) ^ detected during instantiation of "void baz(const std::list<T, std::all ocator<_Elem>> &) [with T=int]"

"Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:covfcf$27q$1@sea.gmane.org...
- Intel 8.0 gives lots of warnings and an internal error without the defect
I should have learned by now -- Intel 8.0 for Windows. Jonathan

Jonathan Turkanis wrote:
- VC8.0 (beta) crashes without BOOST_FOREACH_NO_CONST_RVALUE_DETECTION defined - Comeau 4.3.3 gives two warning and an internal error regardless of whether the defect macro is defined (see end off message) - Intel 8.0 gives lots of warnings and an internal error without the defect macro, but works fine with the defect macro defined (see end off message)
Thanks, Jonathan! I've applied the work-around for Intel Win, and made a change that should hopefully eliminate the warnings. I'm totally at a loss for the Comeau ICE -- that's rather troubling. I'll see if I can get my hands on this compiler and find a work-around. -- Eric Niebler Boost Consulting www.boost-consulting.com

"Eric Niebler" <eric@boost-consulting.com> wrote:
I'm not sure how serious this problem is. If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears.
Here's a version that doesn't pass non-PODs through ellipses. Jonathan begin 666 is_lvalue.cpp M(VEN8VQU9&4@/'-T<FEN9SX-"B-I;F-L=61E(#QB;V]S="]U=&EL:71Y+V5N M86)L95]I9BYH<' ^#0HC:6YC;'5D92 \8F]O<W0O<W1A=&EC7V%S<V5R="YH M<' ^#0HC:6YC;'5D92 \8F]O<W0O='EP95]T<F%I=',O:7-?8V]N<W0N:'!P M/@T*(VEN8VQU9&4@/&)O;W-T+W1Y<&5?=')A:71S+V1E=&%I;"]Y97-?;F]? M='EP92YH<' ^#0H-"FYA;65S<&%C92!B;V]S="![(&YA;65S<&%C92!D971A M:6P@>PT*#0IS=')U8W0@86YY7V-O;G9E<G-I;VX@+R\@9G)O;2!T>7!E7W1R M86ET<R]I<U]C;VYV97)T:6)L92YH<' -"GL-"B @("!T96UP;&%T92 \='EP M96YA;64@5#X@86YY7V-O;G9E<G-I;VXH8V]N<W0@5"8I.PT*(" @('1E;7!L M871E(#QT>7!E;F%M92!4/B!A;GE?8V]N=F5R<VEO;BA4)BD[#0I].PT*#0IT M96UP;&%T93QT>7!E;F%M92!4/@T*='EP95]T<F%I=',Z.GEE<U]T>7!E(&QV M86QU95]T97-T,2A4)BD[#0H-"G1E;7!L871E/'1Y<&5N86UE(%0^#0IT>7!E M7W1R86ET<SHZ;F]?='EP92!L=F%L=65?=&5S=#$H8V]N<W0@5"8I.PT*#0IT M>7!E7W1R86ET<SHZ;F]?='EP92!L=F%L=65?=&5S=#(H86YY7V-O;G9E<G-I M;VX@+BXN*3L-"@T*=&5M<&QA=&4\='EP96YA;64@5#X-"G1Y<&5?=')A:71S M.CIY97-?='EP92 -"FQV86QU95]T97-T,B@@5"8L(&EN="P-"B @(" @(" @ M(" @(" @='EP96YA;64@#0H@(" @(" @(" @(" @(&5N86)L95]I9CP-"B @ M(" @(" @(" @(" @(" @(&ES7V-O;G-T/%0^#0H@(" @(" @(" @(" @(#XZ M.G1Y<&4J(#T@," I.PT*#0I]('T@+R\@;F%M97-P86-E+@T*#0HC9&5F:6YE M($)/3U-47TE37TQ604Q512AX*2!<#0H@(" @*"!S:7IE;V8H8F]O<W0Z.F1E M=&%I;#HZ;'9A;'5E7W1E<W0Q*'@I*2 ]/2!<#0H@(" @("!S:7IE;V8H8F]O M<W0Z.G1Y<&5?=')A:71S.CIY97-?='EP92D@*2!\?"!<#0H@(" @*"!S:7IE M;V8H8F]O<W0Z.F1E=&%I;#HZ;'9A;'5E7W1E<W0R*'@L(# I*2 ]/2!<#0H@ M(" @("!S:7IE;V8H8F]O<W0Z.G1Y<&5?=')A:71S.CIY97-?='EP92D@*2!< M#0H@(" @+RHJ+PT*#0II;G0@9B@I('L@<F5T=7)N(# [('T-"@T*<W1D.CIS M=')I;F<@9R@I('L@<F5T=7)N(")H96QL;R([('T-"F-O;G-T('-T9#HZ<W1R M:6YG(&@H*2![(')E='5R;B B:&5L;&\B.R!]#0H-"FEN="!M86EN*"D-"GL@ M(" -"B @("!I;G0@:3$[#0H@(" @8V]N<W0@:6YT(&DR(#T@,#L-"B @("!S M=&0Z.G-T<FEN9R!S,3L-"B @("!S=&0Z.G-T<FEN9R!A<G)A>5LQ,%T[#0H@ M(" @8V]N<W0@<W1D.CIS=')I;F<@<S(@/2 B:&5L;&\B.PT*(" @($)/3U-4 M7U-4051)0U]!4U-%4E0H0D]/4U1?25-?3%9!3%5%*&DQ*2D[#0H@(" @0D]/ M4U1?4U1!5$E#7T%34T525"A"3T]35%])4U],5D%,544H:3(I*3L-"B @("!" M3T]35%]35$%424-?05-315)4*$)/3U-47TE37TQ604Q512AS,2DI.PT*(" @ M($)/3U-47U-4051)0U]!4U-%4E0H0D]/4U1?25-?3%9!3%5%*',R*2D[#0H@ M(" @0D]/4U1?4U1!5$E#7T%34T525"A"3T]35%])4U],5D%,544H87)R87DI M*3L-"B @("!"3T]35%]35$%424-?05-315)4*"%"3T]35%])4U],5D%,544H M9B@I*2D[#0H@(" @0D]/4U1?4U1!5$E#7T%34T525"@A0D]/4U1?25-?3%9! M3%5%*&<H*2DI.PT*(" @($)/3U-47U-4051)0U]!4U-%4E0H(4)/3U-47TE3 M7TQ604Q512AH*"DI*3L-"B @("!"3T]35%]35$%424-?05-315)4*"%"3T]3 ;5%])4U],5D%,544H(FAE;&QO(BDI.PT*?0T* ` end

Eric Niebler wrote:
If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears.
See the contents of boost/iterator/is_lvalue_iterator.hpp -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Eric Niebler wrote:
If anyone knows of a foolproof way to distinguish lvalues from rvalues, I'm all ears.
See the contents of boost/iterator/is_lvalue_iterator.hpp
Sorry to break this to you Dave, but is_lvalue_iterator suffers from the same problem as BOOST_FOREACH. Consider: struct rvalue_iterator : std::iterator< std::forward_iterator_tag , std::list<int> , ptrdiff_t , std::list<int> const * , std::list<int> const & > { std::list<int> const operator*() const; }; BOOST_STATIC_ASSERT( ! boost::is_lvalue_iterator<rvalue_iterator>::value ); The static assert fails. Since operator* returns a /const/ UDT, it binds to T&, which fools your lvalue detection scheme. I don't know enough about iterator requirements to say whether operator* is permitted to return a const-qualified object of value_type, but regardless, it's still a problem for BOOST_FOREACH. Any other thoughts? -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Vladimir Prus wrote:
Eric, I've some questions about BOOST_FOREACH (which is pretty cool, BTW).
Thanks!
I've been wanting to ask this before: Shouldn't this be spelled: BOOST_FOR_EACH? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
I've been wanting to ask this before: Shouldn't this be spelled: BOOST_FOR_EACH?
Sure, if that's what people prefer. It's only BOOST_FOREACH because it is approximating the "foreach" keyword that some languages have, which might serve to emphasize that it works like a new keyword and not like an STL algorithm. It's also one less character. But those are both exceedingly lame reasons. I don't care either way. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
Vladimir Prus wrote:
Eric, I've some questions about BOOST_FOREACH (which is pretty cool, BTW).
Thanks!
1. Is it possible to use typeof on gcc, to avoid any possible overhead? While you've posted some results which show that gcc generally can optimise it very well, I'd like to be 100% sure). Something like:
#define FOR_EACH(var, container) \ for(typeof(container.begin()) _for_each_i = container.begin(),\ _for_each_e = container.end();\ _for_each_i != _for_each_e; ++_for_each_i)\ if(bool _for_each_continue = false) {}\ else\ for(var = *_for_each_i; !_for_each_continue; _for_each_continue=true)
which works perfectly for me.
Why not use boost::range? Then boost::begin(container)...

Neal D. Becker wrote:
#define FOR_EACH(var, container) \ for(typeof(container.begin()) _for_each_i = container.begin(),\ _for_each_e = container.end();\ _for_each_i != _for_each_e; ++_for_each_i)\ if(bool _for_each_continue = false) {}\ else\ for(var = *_for_each_i; !_for_each_continue; _for_each_continue=true)
which works perfectly for me.
Why not use boost::range? Then boost::begin(container)...
Because: * the above works for me * boost.range is not in sandbox <hint> - Volodya

Jonathan Turkanis wrote:
"Vladimir Prus" <ghost@cs.msu.su> wrote in message news:con9gs$jpp$1@sea.gmane.org...
Neal D. Becker wrote:
Why not use boost::range? Then boost::begin(container)...
Because:
* boost.range is not in sandbox <hint>
Boost.Range is in 1.32
Shame on me! I confused boost::range with range template library that John Torjo is developing. Yes, using boost::range would be better. - Volodya
participants (7)
-
David Abrahams
-
Eric Niebler
-
Jody Hagins
-
Joel de Guzman
-
Jonathan Turkanis
-
Neal D. Becker
-
Vladimir Prus