
I'm kind of loosing faith that this list ever responds to questions but here goes anyway. I've narrowed a problem down to this: #include <iostream> #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> struct test_b { test_b() { std::cerr << "test_b::test_b()\n"; } test_b(test_b const&) { std::cerr << "test_b::test_b(test_b const&)\n"; } virtual int f() = 0; //{ return 5; } }; struct test_d : test_b { test_d() : test_b() { std::cerr << "test_d::test_d()\n"; } test_d(test_d const& d) : test_b(d) { std::cerr << "test_d::test_d(test_d const&)\n"; } int f() { return 5; } }; int main(void) { namespace l = boost::lambda; test_b & td = test_d(); std::cerr << "Value: " << (l::bind(&test_b::f, l::_1))(td) << "\n"; int x; std::cin >> x; } Compiler result: cannot instantiate abstract class test_b. Because lambda doesn't seem to be able to handle smart pointers at all I have been trying to come up with a way to pass the dereferenced result into the function call. Nothing is working. In the end lambda must be able to handle the above in order to make this work. If lambda cannot handle this simple case I just don't see how it can be any use. The full compiler output follows: 1>c:\boost\include\boost-1_33_1\boost\tuple\detail\tuple_basic.hpp(419) : error C2259: 'test_b' : cannot instantiate abstract class 1> due to following members: 1> 'int test_b::f(void)' : is abstract 1> c:\documents and settings\nroberts\my documents\visual studio 2005\projects\playground\playground\playground.cpp(14) : see declaration of 'test_b::f' 1> c:\boost\include\boost-1_33_1\boost\tuple\detail\tuple_basic.hpp(329) : see reference to class template instantiation 'boost::tuples::cons<HT,TT>' being compiled 1> with 1> [ 1> HT=test_b, 1> TT=boost::lambda::detail::deduce_non_ref_argument_types_<boost::tuples::cons<const boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>::tail_type,boost::tuples::tuple<test_b &,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>::type 1> ] 1> c:\boost\include\boost-1_33_1\boost\lambda\detail\lambda_functor_base.hpp(151) : see reference to class template instantiation 'boost::tuples::cons<HT,TT>' being compiled 1> with 1> [ 1> HT=int (__thiscall test_b::* const )(void), 1> TT=boost::tuples::cons<test_b,boost::lambda::detail::deduce_non_ref_argument_types_<boost::tuples::cons<const boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>::tail_type,boost::tuples::tuple<test_b &,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>::type> 1> ] 1> c:\boost\include\boost-1_33_1\boost\lambda\detail\lambda_functor_base.hpp(228) : see reference to class template instantiation 'boost::lambda::detail::has_null_type<Tuple>' being compiled 1> with 1> [ 1> Tuple=boost::tuples::cons<int (__thiscall test_b::* const )(void),boost::tuples::cons<test_b,boost::lambda::detail::deduce_non_ref_argument_types_<boost::tuples::cons<const boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::tuples::detail::map_tuple_to_cons<boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>::type>::tail_type,boost::tuples::tuple<test_b &,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type>>::type>> 1> ] 1> c:\boost\include\boost-1_33_1\boost\lambda\detail\lambda_functor_base.hpp(398) : see reference to class template instantiation 'boost::lambda::detail::deduce_non_ref_argument_types<Args,SigArgs>' being compiled 1> with 1> [ 1> Args=boost::tuples::tuple<int (__thiscall test_b::* const )(void),const boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type>, 1> SigArgs=boost::tuples::tuple<test_b &,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> 1> ] 1> c:\documents and settings\nroberts\my documents\visual studio 2005\projects\playground\playground\playground.cpp(32) : see reference to class template instantiation 'boost::lambda::lambda_functor_base<Act,Args>::sig<SigArgs>' being compiled 1> with 1> [ 1> Act=boost::lambda::action<2,boost::lambda::function_action<2>>, 1> Args=boost::tuples::tuple<int (__thiscall test_b::* const )(void),const boost::lambda::lambda_functor<boost::lambda::placeholder<1>>,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type,boost::lambda::detail::bind_traits<boost::tuples::null_type>::type>, 1> SigArgs=boost::tuples::tuple<test_b &,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> 1> ]

Hello Noah, ----- Mensaje original ----- De: Noah Roberts <roberts.noah@gmail.com> Fecha: Miércoles, Noviembre 29, 2006 11:49 pm Asunto: [Boost-users] more lambda issues Para: boost-users@lists.boost.org
I'm kind of loosing faith that this list ever responds to questions but here goes anyway.
I've narrowed a problem down to this:
[...]
std::cerr << "Value: " << (l::bind(&test_b::f, l::_1))(td) << "\n"; [...] Compiler result: cannot instantiate abstract class test_b.
I haven't been following your investigations into the Boost Lambda Library so excuse me if he following is not relevant: your example can be made to work by using boost::reference_wrappers: #include <iostream> #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> #include <boost/ref.hpp> struct test_b { test_b() { std::cerr << "test_b::test_b()\n"; } test_b(test_b const&) { std::cerr << "test_b::test_b(test_b const&) \n"; } virtual int f() = 0; //{ return 5; } }; struct test_d : test_b { test_d() : test_b() { std::cerr << "test_d::test_d()\n"; } test_d(test_d const& d) : test_b(d) { std::cerr << "test_d::test_d(test_d const&)\n"; } int f() { return 5; } }; int main(void) { namespace l = boost::lambda; test_d tdo; test_b & td = tdo; std::cerr << "Value: " << (l::bind(&test_b::f, l::_1))(boost::ref(td)) << "\n"; int x; std::cin >> x; } Another acceptable syntax that does not use reference wrappers is the following: std::cerr << "Value: " << (&l::_1->*&test_b::f)(td)() << "\n"; HTH, Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

On 11/29/06, "JOAQUIN LOPEZ MU?Z" <joaquin@tid.es> wrote: First, thank you for your response.
std::cerr << "Value: " << (l::bind(&test_b::f, l::_1))(boost::ref(td)) << "\n";
Well, I tried putting ref on the other side but this works...my way didn't. Now I would need to find how to use this solution for my original problem when td is actually a shared_ptr to an abstract base: boost::shared_ptr<test_b> td = boost::shared_ptr<test_b>(new test_d); This does not work: l::bind(l::bind(&test_b::f, l::_1), boost::ref(*l::_1))(td) Unlike boost::bind, lambda::bind doesn't work like this: l::bind(&test_b::f, l::_1)(td) This does but can't be used in an algorithm on a container holding smart pointers: l::bind(&test_b::f, l::_1)(boost::ref(*td)) Interestingly, boost::bind has an operator == that will allow me to compare the result of f() to a value just fine...I thought I needed lambda for this. Boost::bind doesn't suffer from an inability to work directly with smart pointers and doesn't require special magic to use them vs. raw vs. non-ptr. So my original problem is solved by tossing lambda out the airlock but it might be worthwhile to find a way to accomplish a smart pointer member call with lambda for the future. So in the end, my problem is thus: std::find_if(cont.begin(), cont.end(), bind(&deref_val_type::f, _1) == 5); How is that accomplished with lambda if cont holds smart pointers? So far I haven't found any way...

Noah Roberts ha escrito: [...]
So in the end, my problem is thus:
std::find_if(cont.begin(), cont.end(), bind(&deref_val_type::f, _1) == 5);
How is that accomplished with lambda if cont holds smart pointers? So far I haven't found any way...
OK, you can write it with Boost Lambda as follows: namespace l = boost::lambda; std::find_if( cont.begin(), cont.end(), l::bind<int>(&*l::_1->*&deref_val_type::f)==5); Boost.Bind is smarter here, since Boost Lambda needs assistance in: 1. Determining the return type of deref_val_type::f (hence the <int> in l::bind<int>.) 2. Dereferencing the shared_ptr, hence the use of &*l::_1 to get a plain pointer from the shared_ptr, combined with ->* to call deref_val_type::f Others might find terser ways to express this with Boost Lambda, but looks like Boost.Bind is a clear winner here. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

Joaquín Mª López Muñoz wrote:
Noah Roberts ha escrito:
[...]
So in the end, my problem is thus:
std::find_if(cont.begin(), cont.end(), bind(&deref_val_type::f, _1) == 5);
How is that accomplished with lambda if cont holds smart pointers? So far I haven't found any way...
OK, you can write it with Boost Lambda as follows:
namespace l = boost::lambda;
std::find_if( cont.begin(), cont.end(), l::bind<int>(&*l::_1->*&deref_val_type::f)==5);
bind( &deref_val_type::f, *_1 ) == 5 may work with Lambda. I remember patching it so that *_1 works for shared_ptr. I looked into making lambda::bind( &deref_val_type::f, _1 ) work but got lost in the source and gave up. :-) There's always the less elegant lambda::bind( mem_fn( &deref_val_type::f ), _1 ) approach, of course.

Peter Dimov ha escrito:
Joaquín Mª López Muñoz wrote:
Noah Roberts ha escrito:
[...]
So in the end, my problem is thus:
std::find_if(cont.begin(), cont.end(), bind(&deref_val_type::f, _1) == 5);
How is that accomplished with lambda if cont holds smart pointers? So far I haven't found any way...
OK, you can write it with Boost Lambda as follows:
namespace l = boost::lambda;
std::find_if( cont.begin(), cont.end(), l::bind<int>(&*l::_1->*&deref_val_type::f)==5);
bind( &deref_val_type::f, *_1 ) == 5 may work with Lambda.
Almost: the translation of the expression to the lambda world, i.e. l::bind( &deref_val_type::f, *l::_1 ) == 5 (assuming namespace l = boost::lambda) fails to compile because it indices the declaration of boost::tuples::cons<deref_val_type, boost::tuples::null_type>::head which is not instantiable deref_val_type is abstract. The closest I can get in BLL to your formulation is: l::bind( &deref_val_type::f, &*l::_1 ) == 5 which works as expected. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo

On 11/30/06, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
bind( &deref_val_type::f, *_1 ) == 5 may work with Lambda.
Almost: the translation of the expression to the lambda world, i.e.
l::bind( &deref_val_type::f, *l::_1 ) == 5
(assuming namespace l = boost::lambda) fails to compile because it indices the declaration of
boost::tuples::cons<deref_val_type, boost::tuples::null_type>::head
which is not instantiable deref_val_type is abstract.
Right, works fine until working with abstract types. Kind of frustrating to toss it into a test with mock objects and not realize you also need to test that your algorithms work with abstract interfaces. The closest I
can get in BLL to your formulation is:
l::bind( &deref_val_type::f, &*l::_1 ) == 5
which works as expected.
Yep, that works. Not exactly what I wanted to see, and I should have thought of it, but there it is. I think this is something the lambda folks might want to work on as it isn't exactly favorable (is it in the works?). Bind is a lot easier to work with because it catches on.

On Nov 30, 2006, at 11:38 AM, Noah Roberts wrote:
On 11/30/06, Joaquín Mª López Muñoz <joaquin@tid.es> wrote:
bind( &deref_val_type::f, *_1 ) == 5 may work with Lambda.
Almost: the translation of the expression to the lambda world, i.e.
l::bind( &deref_val_type::f, *l::_1 ) == 5
(assuming namespace l = boost::lambda) fails to compile because it indices the declaration of
boost::tuples::cons<deref_val_type, boost::tuples::null_type>::head
which is not instantiable deref_val_type is abstract.
Right, works fine until working with abstract types. Kind of frustrating to toss it into a test with mock objects and not realize you also need to test that your algorithms work with abstract interfaces.
The closest I
can get in BLL to your formulation is:
l::bind( &deref_val_type::f, &*l::_1 ) == 5
which works as expected.
Yep, that works. Not exactly what I wanted to see, and I should have thought of it, but there it is. I think this is something the lambda folks might want to work on as it isn't exactly favorable (is it in the works?).
On the list... needs a non-trivial amount of changes Jaakko
Bind is a lot easier to work with because it catches on. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (5)
-
"JOAQUIN LOPEZ MU?Z"
-
Jaakko Jarvi
-
Joaquín Mª López Muñoz
-
Noah Roberts
-
Peter Dimov