Converting loop to using boost::lambda where containers has boost::shared_ptrs
I have a loop which I am trying to convert to using a boost::lambda
function.
typedef std::vector< boost::shared_ptr
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Stephen Torri Sent: Friday, May 18, 2007 9:01 PM To: boost-users Subject: [Boost-users] Converting loop to using boost::lambda where containers has boost::shared_ptrs
My idea was to do:
std::for_each ( m_data.begin(), m_data.end(), output << (_1 ->* &Verification_Type_Info::to_String) ( new_indent_limit ) );
[Nat] I think the construct you want will look more like (untested): std::for_each(m_data.begin(), m_data.end(), output << boost::bind(&Verification_Type_Info::to_String, _1, new_indent_limit));
On Sat, 2007-05-19 at 09:34 -0400, Nat Goodspeed wrote:
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Stephen Torri Sent: Friday, May 18, 2007 9:01 PM To: boost-users Subject: [Boost-users] Converting loop to using boost::lambda where containers has boost::shared_ptrs
My idea was to do:
std::for_each ( m_data.begin(), m_data.end(), output << (_1 ->* &Verification_Type_Info::to_String) ( new_indent_limit ) );
[Nat] I think the construct you want will look more like (untested):
std::for_each(m_data.begin(), m_data.end(), output << boost::bind(&Verification_Type_Info::to_String, _1, new_indent_limit));
Its close but not quite. I get an error message that _1 is ambiguous Append_Frame.cpp:48: error: reference to '_1' is ambiguous /usr/include/boost/lambda/core.hpp:69: error: candidates are: const boost::lambda::placeholder1_type& boost::lambda::<unnamed>::_1 /usr/include/boost/bind/placeholders.hpp:54: error: boost::arg<1> <unnamed>::_1 Stephen
On 19/05/07, Stephen Torri
On Sat, 2007-05-19 at 09:34 -0400, Nat Goodspeed wrote:
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Stephen Torri Sent: Friday, May 18, 2007 9:01 PM To: boost-users Subject: [Boost-users] Converting loop to using boost::lambda where containers has boost::shared_ptrs
My idea was to do:
std::for_each ( m_data.begin(), m_data.end(), output << (_1 ->* &Verification_Type_Info::to_String) ( new_indent_limit ) );
[Nat] I think the construct you want will look more like (untested):
std::for_each(m_data.begin(), m_data.end(), output << boost::bind(&Verification_Type_Info::to_String, _1, new_indent_limit));
Its close but not quite. I get an error message that _1 is ambiguous
Append_Frame.cpp:48: error: reference to '_1' is ambiguous /usr/include/boost/lambda/core.hpp:69: error: candidates are: const boost::lambda::placeholder1_type& boost::lambda::<unnamed>::_1 /usr/include/boost/bind/placeholders.hpp:54: error: boost::arg<1> <unnamed>::_1
Stephen
Nat's using Boost.Bind, not the bind in Boost.Lambda - they both
define _1 as a placeholder, so they clash...
Using bind from Boost.Lambda, you'll need nested binds to cope with shared_ptr:
using namespace boost::lambda;
std::for_each(m_data.begin(), m_data.end(),
output << bind(&Verification_Type_Info::to_String,
bind(boost::shared_ptr
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Stuart Dootson Sent: Saturday, May 19, 2007 11:23 AM To: boost-users@lists.boost.org Subject: Re: [Boost-users] Converting loop to using boost::lambda where containers has boost::shared_ptrs
[Nat] I think the construct you want will look more like (untested):
std::for_each(m_data.begin(), m_data.end(), output << boost::bind(&Verification_Type_Info::to_String, _1, new_indent_limit));
Its close but not quite. I get an error message that _1 is ambiguous
Nat's using Boost.Bind, not the bind in Boost.Lambda - they both define _1 as a placeholder, so they clash...
Using bind from Boost.Lambda, you'll need nested binds to cope with shared_ptr:
[Nat] Or you could explicitly qualify _1 in my version: ...boost::bind(&Verification_Type_Info::to_String, boost::bind::_1, new_indent_limit)... I like that boost::bind() knows about shared_ptrs.
On Sat, 2007-05-19 at 11:56 -0400, Nat Goodspeed wrote:
[Nat] Or you could explicitly qualify _1 in my version:
...boost::bind(&Verification_Type_Info::to_String, boost::bind::_1, new_indent_limit)...
I like that boost::bind() knows about shared_ptrs.
I did the following: std::for_each ( m_data.begin(), m_data.end(), output << boost::bind ( &Verification_Type_Info::to_String, boost::bind::_1, new_indent_limit ) ); I get an error that Append_Frame.cpp: In member function 'virtual std::string libreverse::java_module::Append_Frame::to_String(uint32_t) const': Append_Frame.cpp:50: error: 'boost::bind' is not a class or namespace Are you sure that the second argument is boost::bind::_1? I found that _1 is declared in boost/bind/placeholders.hpp as: boost::arg<1> _1; Stephen
On Sat, 2007-05-19 at 11:12 -0500, Stephen Torri wrote:
I get an error that
Append_Frame.cpp: In member function 'virtual std::string libreverse::java_module::Append_Frame::to_String(uint32_t) const': Append_Frame.cpp:50: error: 'boost::bind' is not a class or namespace
Are you sure that the second argument is boost::bind::_1? I found that _1 is declared in boost/bind/placeholders.hpp as:
boost::arg<1> _1;
Stephen
Here is a test program that represents the problem we are trying to
solve. A vector contains boost shared pointers for a base class. For
each item in the container we want to call to_String with a value
representing the number of spaces to indent the output.
#include <string>
#include <sstream>
#include
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Stephen Torri Sent: Saturday, May 19, 2007 12:58 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] Converting loop to usingboost::lambda where containers has boost::shared_ptrs
Here is a test program that represents the problem we are trying to solve.
std::for_each ( m_data.begin(), m_data.end(), std::cout << boost::bind ( &Base::to_String, boost::bind::_1, indent_value ) );
[Nat] Heh. With my VC 7.1 compiler (Version 13.10.3077 according to cl /help), the program you sent produces an ICE. But then I'm still on Boost 1.31.1. On the other hand, since the program you sent makes no mention whatsoever of boost::lambda, you can remove the boost::bind qualification from _1 because there's no ambiguity. I did that, and got an error about trying to insert a boost::bind() expression to std::cout. Which would sort of toss us back towards boost::lambda. I thought I'd try using boost::bind on the insertion operator anyway: std::for_each ( m_data.begin(), m_data.end(), boost::bind(operator<<, boost::ref(std::cout), boost::bind ( &Base::to_String, _1, indent_value ) )); but the compiler wasn't buying it. So... maybe there's a way to express what I was trying to write above, or maybe there's a way to express Stuart's boost::lambda::bind construct. But for myself, in this situation I'd consider an explicit 'for' loop the clearest expression of intent. C++ is a truly amazing language that, in many cases, *almost* gets you where you want to go. :-)
On Sat, 2007-05-19 at 14:36 -0400, Nat Goodspeed wrote:
[Nat] Heh. With my VC 7.1 compiler (Version 13.10.3077 according to cl /help), the program you sent produces an ICE. But then I'm still on Boost 1.31.1.
On the other hand, since the program you sent makes no mention whatsoever of boost::lambda, you can remove the boost::bind qualification from _1 because there's no ambiguity. I did that, and got an error about trying to insert a boost::bind() expression to std::cout. Which would sort of toss us back towards boost::lambda.
I thought I'd try using boost::bind on the insertion operator anyway:
std::for_each ( m_data.begin(), m_data.end(), boost::bind(operator<<, boost::ref(std::cout), boost::bind ( &Base::to_String, _1, indent_value ) ));
but the compiler wasn't buying it.
So... maybe there's a way to express what I was trying to write above, or maybe there's a way to express Stuart's boost::lambda::bind construct.
But for myself, in this situation I'd consider an explicit 'for' loop the clearest expression of intent.
C++ is a truly amazing language that, in many cases, *almost* gets you where you want to go. :-)
I am glad to know I still the have skill of breaking compilers. :) I will leave things as a loop until I hear about any other better solution. Thanks for the help. Stephen
I am glad to know I still the have skill of breaking compilers. :)
Well, I seem to have similar skills. The code below crashes my compiler ( VC7.1 SP 1), as well. void print( const std::string& s ) { std::cout << s; } int main ( int, char** ) { typedef boost::shared_ptr<A> A_ptr_t; typedef boost::shared_ptr<D> D_ptr_t; typedef std::vector < boost::shared_ptr<Base> > Data_t; Data_t m_data; A_ptr_t a ( new A ( 50 ) ); D_ptr_t d ( new D ( 30 ) ); m_data.push_back ( a ); m_data.push_back ( d ); boost::uint32_t indent_value = 4; // this works boost::bind( &print , boost::bind( &Base::to_String , A_ptr_t( new A( 5 ) ) , indent_value ))(); // this doesn't work - ICE std::for_each ( m_data.begin(), m_data.end(), boost::bind( &print , boost::bind( &Base::to_String , boost::bind::_1 , indent_value ))); return 0; } I know this is not the solution. I'm still using a seperate function print() for outputting. I will keep trying to solve that one. On the other hand it would be nice if boost::bind comes some handy function like the print(). Just a thought. Christian
Christian, Can you please specify what happens when the compiler crashes? There is a known issue that template intensive code can crash the VC compiler, to resolve it, you can increase the memory heap size used by VC internally. You may read more on it at: http://www.boost.org/doc/html/variant/misc.html#variant.troubleshooting This is not only boost::variant issue and can happen in other libraries as well. Best Regards, Ovanes -----Ursprüngliche Nachricht----- Von: Christian Henning [mailto:chhenning@gmail.com] Gesendet: Sonntag, 20. Mai 2007 00:41 An: boost-users@lists.boost.org Betreff: Re: [Boost-users] Converting loop to using boost::lambda where containers has boost::shared_ptrs
I am glad to know I still the have skill of breaking compilers. :)
Well, I seem to have similar skills. The code below crashes my compiler ( VC7.1 SP 1), as well. void print( const std::string& s ) { std::cout << s; } int main ( int, char** ) { typedef boost::shared_ptr<A> A_ptr_t; typedef boost::shared_ptr<D> D_ptr_t; typedef std::vector < boost::shared_ptr<Base> > Data_t; Data_t m_data; A_ptr_t a ( new A ( 50 ) ); D_ptr_t d ( new D ( 30 ) ); m_data.push_back ( a ); m_data.push_back ( d ); boost::uint32_t indent_value = 4; // this works boost::bind( &print , boost::bind( &Base::to_String , A_ptr_t( new A( 5 ) ) , indent_value ))(); // this doesn't work - ICE std::for_each ( m_data.begin(), m_data.end(), boost::bind( &print , boost::bind( &Base::to_String , boost::bind::_1 , indent_value ))); return 0; } I know this is not the solution. I'm still using a seperate function print() for outputting. I will keep trying to solve that one. On the other hand it would be nice if boost::bind comes some handy function like the print(). Just a thought. Christian _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Ovanes, I know about the /ZmXXX compiler option. Usually the compiler
will report when it's running out of heap space. But in this case the
compiler just crashes.
This is very simple example that crashes the compiler.
#include <iostream>
#include <string>
#include <vector>
#include
Christian,
Can you please specify what happens when the compiler crashes? There is a known issue that template intensive code can crash the VC compiler, to resolve it, you can increase the memory heap size used by VC internally. You may read more on it at:
http://www.boost.org/doc/html/variant/misc.html#variant.troubleshooting
This is not only boost::variant issue and can happen in other libraries as well.
Best Regards, Ovanes
-----Ursprüngliche Nachricht----- Von: Christian Henning [mailto:chhenning@gmail.com] Gesendet: Sonntag, 20. Mai 2007 00:41 An: boost-users@lists.boost.org Betreff: Re: [Boost-users] Converting loop to using boost::lambda where containers has boost::shared_ptrs
I am glad to know I still the have skill of breaking compilers. :)
Well, I seem to have similar skills. The code below crashes my compiler ( VC7.1 SP 1), as well.
void print( const std::string& s ) { std::cout << s; }
int main ( int, char** ) { typedef boost::shared_ptr<A> A_ptr_t; typedef boost::shared_ptr<D> D_ptr_t;
typedef std::vector < boost::shared_ptr<Base> > Data_t; Data_t m_data;
A_ptr_t a ( new A ( 50 ) ); D_ptr_t d ( new D ( 30 ) );
m_data.push_back ( a ); m_data.push_back ( d );
boost::uint32_t indent_value = 4;
// this works boost::bind( &print , boost::bind( &Base::to_String , A_ptr_t( new A( 5 ) ) , indent_value ))();
// this doesn't work - ICE std::for_each ( m_data.begin(), m_data.end(), boost::bind( &print , boost::bind( &Base::to_String , boost::bind::_1 , indent_value )));
return 0; }
I know this is not the solution. I'm still using a seperate function print() for outputting. I will keep trying to solve that one.
On the other hand it would be nice if boost::bind comes some handy function like the print(). Just a thought.
Christian _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Thanks a lot, again. ;-)
This is the working code now.
#include <string>
#include <sstream>
#include
Christian Henning
Thanks a lot, again.
This is the working code now. [cut]
You can use transform + ostream_iterator instead of for_each + print. transform( m_data.begin() , m_data.end() , ostream_iterator<string>(cout, "\n") , boost::bind( &Base::to_String , _1 , indent_value)); And instead of handcrafted loop for indentation you can use constructor of std::string. virtual string to_String ( boost::uint32_t indent ) { stringstream output; output << string(indent, ' ') << m_value; return output.str(); } Roman Perepelitsa.
Thanks Roman. Will do.
On 5/21/07, Roman Perepelitsa
Christian Henning
writes: Thanks a lot, again.
This is the working code now. [cut]
You can use transform + ostream_iterator instead of for_each + print.
transform( m_data.begin() , m_data.end() , ostream_iterator<string>(cout, "\n") , boost::bind( &Base::to_String , _1 , indent_value));
And instead of handcrafted loop for indentation you can use constructor of std::string.
virtual string to_String ( boost::uint32_t indent ) { stringstream output; output << string(indent, ' ') << m_value; return output.str(); }
Roman Perepelitsa.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
The following solution doesn't use boost::lambda anymore. Also the
Base class is abstract again. So, I think this solution is better:
#include <string>
#include <sstream>
#include
Alright, I solved it. Two small changes in the code did it. Hope they
are not too bad for you.
First I needed to remove the =0 statement for the to_string in your
base class. If I don't do that I can the following error:
c:\boost_1_34_0\boost\tuple\detail\tuple_basic.hpp(328) : error C2259:
'Base' : cannot instantiate abstract class
[snip]
So my base class looks like as follows:
class Base {
public:
virtual std::string to_String ( boost::uint32_t indent )
{ return "" ;}
};
Second change was to remove the boost::bind lib and to use lambda's
bind. I also needed to add an asterisk to _1.
Here is the complete code that works on my machine.
#include <string>
#include <sstream>
#include
Thanks for the help. Roman's idea of using std::string constructor is better than a handcrafted loop. I just got my mind into a trap thinking I had to create a loop. I don't see the need to change the base class to_String to a function. My intention is to leave it as it is since vc8 and gcc both compile it fine. Stephen On Sun, 2007-05-20 at 22:30 -0400, Christian Henning wrote:
Alright, I solved it. Two small changes in the code did it. Hope they are not too bad for you.
First I needed to remove the =0 statement for the to_string in your base class. If I don't do that I can the following error:
c:\boost_1_34_0\boost\tuple\detail\tuple_basic.hpp(328) : error C2259: 'Base' : cannot instantiate abstract class [snip]
So my base class looks like as follows:
class Base { public:
virtual std::string to_String ( boost::uint32_t indent ) { return "" ;} };
Second change was to remove the boost::bind lib and to use lambda's bind. I also needed to add an asterisk to _1.
Here is the complete code that works on my machine.
#include <string> #include <sstream> #include
#include <vector> #include #include #include #include <iostream> using namespace boost::lambda;
class Base { public:
virtual std::string to_String ( boost::uint32_t indent ) { return "" ;} };
class A : public Base { public:
A ( boost::uint32_t value ) : m_value ( value ) {}
virtual std::string to_String ( boost::uint32_t indent ) { std::stringstream output;
for ( boost::uint32_t i = 0; i < indent; i++ ) { output << " "; }
output << m_value;
return output.str(); }
private:
boost::uint32_t m_value; };
class D : public Base { public:
D ( boost::uint32_t value ) : m_value ( value ) {}
virtual std::string to_String ( boost::uint32_t indent ) { std::stringstream output;
for ( boost::uint32_t i = 0; i < indent; i++ ) { output << " "; }
output << m_value;
return output.str(); }
private:
boost::uint32_t m_value; };
const char* print( const std::string& s ) { return s.c_str(); }
int main ( int, char** ) { typedef boost::shared_ptr<A> A_ptr_t; typedef boost::shared_ptr<D> D_ptr_t;
typedef std::vector < boost::shared_ptr<Base> > Data_t; Data_t m_data;
A_ptr_t a ( new A ( 50 ) ); D_ptr_t d ( new D ( 30 ) );
m_data.push_back ( a ); m_data.push_back ( d );
boost::uint32_t indent_value = 4;
std::for_each ( m_data.begin(), m_data.end(), std::cout << bind( &Base::to_String, *_1, indent_value ) ); return 0; }
Regards, Christian _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Sat, 2007-05-19 at 16:23 +0100, Stuart Dootson wrote:
Its close but not quite. I get an error message that _1 is ambiguous
Append_Frame.cpp:48: error: reference to '_1' is ambiguous /usr/include/boost/lambda/core.hpp:69: error: candidates are: const boost::lambda::placeholder1_type& boost::lambda::<unnamed>::_1 /usr/include/boost/bind/placeholders.hpp:54: error: boost::arg<1> <unnamed>::_1
Stephen
Nat's using Boost.Bind, not the bind in Boost.Lambda - they both define _1 as a placeholder, so they clash...
Using bind from Boost.Lambda, you'll need nested binds to cope with shared_ptr:
using namespace boost::lambda; std::for_each(m_data.begin(), m_data.end(), output << bind(&Verification_Type_Info::to_String, bind(boost::shared_ptr
::get, _1), new_indent_limit));
I think we are closer. Append_Frame.cpp: In member function 'virtual std::string libreverse::java_module::Append_Frame::to_String(uint32_t) const': Append_Frame.cpp:50: error: invalid use of non-static member function 'T* boost::shared_ptr<T>::get() const [with T = libreverse::java_module::Verification_Type_Info]' make[6]: *** [libio_java_class_la-Append_Frame.lo] Error 1 I am not sure the second bind is doing what you wanted. Stephen
participants (7)
-
Christian Henning
-
Nat Goodspeed
-
Ovanes Markarian
-
Peter Dimov
-
Roman Perepelitsa
-
Stephen Torri
-
Stuart Dootson