
Dear All, I think I have found a safe way to bind a temporary to a const reference and cast away the constness. This means that a temporary can be passed (relatively) safely to an algorithm with a prototype like void foo( T& t ) { // do something with t, but don't store the reference. } for example, we might want to call foo() like vector<int> make_vec(); foo( make_vec() ); but we cannot. Using a little macro, we can say foo( BOOST_LVALUE( make_vec() ) ); assuming these prototypes const vector<int> make_cvec(); const vector<int>& make_crvec(); these uses will fail at ct foo( BOOST_LVALUE( make_cvec() ) ); foo( BOOST_LVALUE( make_crvec() ) ); Comments are welcome. br Thorsten begin 666 lvalue_cast.cpp M#0HC:6YC;'5D92 \:6]S=')E86T^#0HC:6YC;'5D92 \=F5C=&]R/@T*(VEN M8VQU9&4@/&%L9V]R:71H;3X-"@T*=7-I;F<@;F%M97-P86-E('-T9#L-"G5S M:6YG(&YA;65S<&%C92!B;V]S=#L-"@T*+R\@;75S="!N;W0@8F4@<F5J96-T M960-"G9E8W1O<CQI;G0^('9E8R@I#0I[#0H@(" @=F5C=&]R/&EN=#X@=B@@ M,3 L(#$P("D[#0H@(" @<F5T=7)N('8[#0I]#0H-"B\O(&UU<W0@8F4@<F5J M96-T960-"F-O;G-T('9E8W1O<CQI;G0^(&-V96,H*0T*>PT*(" @('9E8W1O M<CQI;G0^('8H(#$P+" Q," I.PT*(" @(')E='5R;B!V.PT*?0T*#0HO+R!M M=7-T(&)E(')E:F5C=&5D#0IC;VYS="!V96-T;W(\:6YT/B8@8W)V96,H*0T* M>PT*(" @('-T871I8R!V96-T;W(\:6YT/B!V*" Q,"P@,3 @*3L-"B @("!R M971U<FX@=CL-"GT-"@T*=&5M<&QA=&4\(&-L87-S(%0@/@T*5"8@;'9A;'5E M7V-A<W0H(&-O;G-T(%0F(')V86QU92 I#0I[#0H@(" @<F5T=7)N(&-O;G-T M7V-A<W0\5"8^*"!R=F%L=64@*3L-"GT-"@T*=&5M<&QA=&4\(&-L87-S(%0@ M/@T*=F]I9"!I<U]L=F%L=65?8V%S=%]S869E*"!4("D@#0I[#0H@(" O+PT* M(" @+R\@5V%R;FEN9SH@4F5A9&UE(0T*(" @+R\@:68@>6]U(&=E="!A;B!E M<G)O<B!H97)E+"!I="!M96%N<R!Y;W4G<F4@=')Y:6YG('1O(&-A<W0@87=A M>2!C;VYS="UN97-S(&9R;VT@80T*(" @+R\@8V]N<W0@;V)J96-T+B!9;W4@ M<VEM<&QY(&-A;FYO="!U<V4@0D]/4U1?3%9!3%5%7T-!4U0H*2!S869E;'D@ M=VET:"!T:&4@<')O=FED960G#0H@(" O+R!A<F=U;65N= T*(" @+R\-"GT- M"@T*=&5M<&QA=&4\(&-L87-S(%0@/@T*=F]I9"!I<U]L=F%L=65?8V%S=%]S M869E*"!4)B I#0I[#0H@(" O+PT*(" @+R\@5V%R;FEN9SH@4F5A9&UE(0T* M(" @+R\@:68@>6]U(&=E="!A;B!E<G)O<B!H97)E+"!I="!M96%N<R!Y;W4G M<F4@=')Y:6YG('1O(&-A<W0@87=A>2!C;VYS="UN97-S(&9R;VT@80T*(" @ M+R\@8V]N<W0@;V)J96-T+B!9;W4@<VEM<&QY(&-A;FYO="!U<V4@0D]/4U1? M3%9!3%5%7T-!4U0H*2!S869E;'D@=VET:"!T:&4@<')O=FED960G#0H@(" O M+R!A<F=U;65N= T*(" @+R\@(" @#0I]#0H-"B-D969I;F4@0D]/4U1?3%9! M3%5%*"!E>'!R("D@7 T**&ES7VQV86QU95]C87-T7W-A9F4H(&5X<'(@*2P@ M;'9A;'5E7V-A<W0H(&5X<'(@*2D@#0H-"@T*=&5M<&QA=&4\(&-L87-S($,@ M/@T*=F]I9"!S;W)T*"!#)B!C("D-"GL-"B @("!S;W)T*"!C+F)E9VEN*"DL M(&,N96YD*"D@*3L-"B @("!C;W5T(#P\(")S;W)T960B.PT*?0T*#0II;G0@ M;6%I;B@@:6YT+"!C:&%R*BH@*0T*>PT*(" @('-O<G0H($)/3U-47TQ604Q5 M12@@=F5C*"D@*2 I.PT*(" @("\O(&-T+65R<F]R.@T*(" @("\O<V]R="@@ M0D]/4U1?3%9!3%5%*"!C=F5C*"D@*2 I.PT*(" @("\O<V]R="@@0D]/4U1? H3%9!3%5%*"!C<G9E8R@I("D@*3L-"B @("!R971U<FX@,#L-"GT-"@`` ` end

On Tue, Apr 13, 2004 at 12:26:35AM +1000, Thorsten Ottosen wrote:
I think I have found a safe way to bind a temporary to a const reference and cast away the constness.
This means that a temporary can be passed (relatively) safely to an algorithm with a prototype like ... Comments are welcome.
Cute use of compile-time ambiguity to ensure that you don't try to mutate const objects. Offhand it seems like it is "safe", in the sense of lifetime-of-the-temporary issues. What's an example use-case? I don't recall ever needing/wanting this. -- -Brian McNamara (lorgon@cc.gatech.edu)

Brian McNamara <lorgon@cc.gatech.edu> writes:
On Tue, Apr 13, 2004 at 12:26:35AM +1000, Thorsten Ottosen wrote:
I think I have found a safe way to bind a temporary to a const reference and cast away the constness.
This means that a temporary can be passed (relatively) safely to an algorithm with a prototype like ... Comments are welcome.
Cute use of compile-time ambiguity to ensure that you don't try to mutate const objects.
Offhand it seems like it is "safe", in the sense of lifetime-of-the-temporary issues.
Seems like this would be more useful. template <class T> T& mutate_rvalue(T& x, int) { return x; } template <class T> T& mutate_rvalue(T const& x, ...) { return const_cast<T&>(x); } // test code #include <string> typedef int yes; typedef char* no; template <class T> yes is_mutable(T&); template <class T> no is_mutable(T const&); std::string x; std::string const y; yes a = is_mutable(mutate_rvalue(x,0)); no b = is_mutable(mutate_rvalue(y,0)); yes c = is_mutable(mutate_rvalue(x+y,0));
What's an example use-case? I don't recall ever needing/wanting this.
Howard Hinnant brought up some cases, during LWG discussion of iterator adaptors, where you might want to mutate an object if you had permission to, for example in some linear algebra you might want to do part of the algorithm in-place. If it was generic code you'd want to take the same liberties with rvalues as with mutable lvalues. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uzn9hcgip.fsf@boost-consulting.com... [snip]
Seems like this would be more useful.
Perhaps. Do you care to explain why?
It works generically on lvalues and rvalues, so that if someone hands you a function object f, and some_algo is more efficient when it can modify its first argument in-place, you can do some_algo( mutate_rvalue(f(),0), x ); HTH, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uvfk47i7y.fsf@boost-consulting.com...
"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uzn9hcgip.fsf@boost-consulting.com... [snip]
Seems like this would be more useful.
Perhaps. Do you care to explain why?
It works generically on lvalues and rvalues, so that if someone hands you a function object f, and some_algo is more efficient when it can modify its first argument in-place, you can do
some_algo( mutate_rvalue(f(),0), x );
yeah, definitely an improvement, although I wish there was some way of putting a static assertion in there. The new error message is a lot worse. br Thorsten

Thorsten Ottosen wrote:
"David Abrahams" <dave@boost-consulting.com> wrote in message
It works generically on lvalues and rvalues, so that if someone hands you a function object f, and some_algo is more efficient when it can modify its first argument in-place, you can do
some_algo( mutate_rvalue(f(),0), x );
yeah, definitely an improvement, although I wish there was some way of putting a static assertion in there. The new error message is a lot worse.
How about this: template<class T> struct cant_mutate_const_values { typedef int type; }; template<class T> struct cant_mutate_const_values<T const> { typedef typename cant_mutate_const_values::error type; }; template<class T> T& mutate_rvalue(T const& x) { return const_cast<T&>(x); } template<class T> T& mutate_rvalue(T& x, typename cant_mutate_const_values<T>::type = 0) { return x; } -- Daniel Wallin

"Daniel Wallin" <dalwan01@student.umu.se> wrote in message news:407BC506.6020209@student.umu.se...
How about this:
[snip] it's better, although I can't compile it on comeau 4.3. gcc and vc7 seems to like it. I'm know sure there can be made a normal boost-hacked implementation that will work nicely on many platforms. We just someone to do it. br Thorsten

Thorsten Ottosen wrote:
"Daniel Wallin" <dalwan01@student.umu.se> wrote in message news:407BC506.6020209@student.umu.se...
How about this:
[snip]
it's better, although I can't compile it on comeau 4.3. gcc and vc7 seems to like it. I'm know sure there can be made a normal boost-hacked implementation that will work nicely on many platforms. We just someone to do it.
OK, this works on comeau: template<class T> struct cant_mutate_const_values { typedef int type; }; template<class T> struct cant_mutate_const_values<T const> { template<class U> struct error {}; typedef typename error<T>::type type; }; template<class T> T& mutate_rvalue(T const& x) { return const_cast<T&>(x); } template<class T> T& mutate_rvalue(T& x, typename cant_mutate_const_values<T>::type = 0) { return x; } -- Daniel Wallin

"Brian McNamara" <lorgon@cc.gatech.edu> wrote in message news:20040412152352.GA1822@gaia2.cc.gatech.edu... [snip]
What's an example use-case? I don't recall ever needing/wanting this.
My initial use-case was to use it in mutating container algorithms. Without it you would have to create a temporary, even though you didn't need it (and hardcoding the return-type is messy). So it would have been optimal just to hand the result of function to new functions even though they mutate, eg vector<int> vec(); my_copy( my_sort( my_unique( vec() ) ), ostream_iterator<int>( cout ) ); instead of vector<int> temp1( vec() ); vector<int> temp2( my_unique( temp1 ) ); my_copy( my_sort( temp2 ), .... ) br Thorsten

"Thorsten Ottosen" <nesotto@cs.auc.dk> wrote in message news:c5fdhk$f2n$1@sea.gmane.org... [snip] Doh!
vector<int> vec();
my_copy( my_sort( my_unique( vec() ) ), ostream_iterator<int>( cout ) );
my_copy( my_sort( BOOST_LVALUE( my_unique( BOOST_LVALUE( vec() ) ) ) ), ostream_iterator<int>( cout ) );
instead of
vector<int> temp1( vec() ); vector<int> temp2( my_unique( temp1 ) ); my_copy( my_sort( temp2 ), .... )
br Thorsten

Thorsten Ottosen wrote:
I think I have found a safe way to bind a temporary to a const reference and cast away the constness.
template< class T > void is_lvalue_cast_safe( T ) {} template< class T > void is_lvalue_cast_safe( T& ) {} So, if you pass non-const rvalue the second overload can't be used and everything's OK. When passing const rvalue T will be "const" in the second overload and you get ambiguity. That's cute. I wonder if all current compilers are smart enough to not call copy constructor when passing parameter? At least all gcc versions I have, starting with 2.95 avoid the copy. When looking at: my_copy( my_sort( BOOST_LVALUE( my_unique( BOOST_LVALUE( vec() ) ) ) ), ostream_iterator<int>( cout ) ); I wish we can get away from BOOST_LVALUE too. The simple approach of: template<class T> void sort(T t) {} template<class T> void sort(T& t) {} does not really work, since there's ambiguity when passing non-const reference. It's probably possible to use mojo to distinguish non-const lvalues, const objects and non-const temporary and then add compile-time fail inside version which is selected for const objects. But we can't change definition of std::vector :-( - Volodya

"Vladimir Prus" <ghost@cs.msu.su> wrote in message news:c5g491$ig4$1@sea.gmane.org...
I wish we can get away from BOOST_LVALUE too. The simple approach of:
template<class T> void sort(T t) {}
template<class T> void sort(T& t) {}
does not really work, since there's ambiguity when passing non-const reference
One is a language change like &&. If we had template<class T> void sort(T t) {} template<class T> void sort(T& t) {} template< class T > void sort( const T& t ) wouldn't it be possible to enable/disable certain combination in certain situaltions, so it would just work ? Anyway, my brain has stopped thinking, so I'll better do some homework. br Thorsten
participants (5)
-
Brian McNamara
-
Daniel Wallin
-
David Abrahams
-
Thorsten Ottosen
-
Vladimir Prus