Search code examples
c++boostabstract-classshared-ptrboost-lambda

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>


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

Solution

  • 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.