boost::lambda expression fails to compile because of instantiation of abstract template arg. Any explanation and/or work arounds?
I'm in the process of learning boost::lambda and I've managed to create a situation that I can't resolve with what I know so far.
Apparently in the bowels of boost::lambda, the following example causes the attempted instantiation of abstract class AbstractFoo, and prevents the lambda expression from compiling. The problem is that I don't know why it is trying to instantiate it so I cant try to work around it.
Any boost::lambda experts that can:
- give me a clue as to why this is happening?
- suggest a work around?
Example:
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp开发者_JAVA技巧>
struct AbstractFoo
{
typedef boost::shared_ptr<AbstractFoo> Ptr;
virtual int it() const = 0;
};
struct Bar : public AbstractFoo
{
typedef boost::shared_ptr<Bar> Ptr;
virtual int it() const { return 3; }
};
typedef AbstractFoo Foo; // Comment this out
//typedef Bar Foo; // and this in to make this example compilable
int main()
{
namespace bll = boost::lambda;
boost::function< bool (const Foo::Ptr &)> func;
func = (bll::protect(bll::bind( &Foo::it, *bll::_1))(bll::_1) == 3);
return 0;
}
This fails to compile (on gcc 4.4.3, boost 1_40) with a monster template error the important part of which seems to be:
error: cannot declare field
‘boost::tuples::cons<AbstractFoo,boost::tuples::null_type>::head’
to be of abstract type ‘AbstractFoo’
because the following virtual functions are pure within ‘AbstractFoo’:
virtual int AbstractFoo::it() const
As you discovered, you can not do that, because the object needs to be copied, but in this case it can not be instantiated because it contains a pure virtual method. The simplest solution is to pass it using a pointer :
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <iostream>
struct AbstractFoo
{
typedef boost::shared_ptr<AbstractFoo> Ptr;
virtual int it() const = 0;
};
struct Bar : public AbstractFoo
{
typedef boost::shared_ptr<Bar> Ptr;
virtual int it() const { return 3; }
};
typedef AbstractFoo Foo; // Comment this out
//typedef Bar Foo; // and this in to make this example compilable
int main()
{
namespace bll = boost::lambda;
boost::function< bool ( const Foo * )> func;
func = ( bll::protect( bll::bind( &Foo::it, bll::_1 ) )( bll::_1 ) == 3);
//func = bll::bind( &Foo::it, bll::_1 );
Foo::Ptr p( new Bar );
std::cout << std::boolalpha << func( p.get() ) << std::endl;
}
To be more precise, this :
*bll::_1
needs to instantiate and copy object of type AbstractFoo
Riffing off of JVo's answer, the following works around the issue:
func3 = (bll::protect(bll::bind( &Foo::it,
bll::bind( &Foo::Ptr::get,
bll::_1 ))) (bll::_1) == 2);
where
bll::bind( &Foo::Ptr::get, bll::_1)
Pulls out the pointer so that the place holder is not dereffed in line.
From the comments suggesting compiling without error in VS with Boost 1_47 I might guess that the issue has since been fixed in boost, and that it was a sort of bug.
精彩评论