Не удается скомпилировать выражение boost :: lambda из-за создания абстрактного шаблона arg.Любое объяснение и / или обходные пути? - PullRequest
4 голосов
/ 27 июля 2011

Я нахожусь в процессе обучения boost :: lambda, и мне удалось создать ситуацию, которую я не могу решить с помощью того, что я знаю до сих пор.

Видимо, в недрах boost :: lambda, следующий пример вызывает попытку создания экземпляра абстрактного класса AbstractFoo и предотвращает компиляцию лямбда-выражения. Проблема в том, что я не знаю, почему он пытается создать его экземпляр, поэтому я не могу попытаться обойти это.

Любое повышение :: Лямбда-эксперты, которые могут:

  • Дайте мне понять, почему это происходит?
  • предложить обходной путь?

Пример:

#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;
}

Не удается скомпилировать (в gcc 4.4.3, boost 1_40) ошибку шаблона монстра, важной частью которой является:

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

Ответы [ 2 ]

1 голос
/ 27 июля 2011

Если исходить из ответа JVo, то вокруг этой проблемы работает следующее:

func3 = (bll::protect(bll::bind( &Foo::it, 
                                 bll::bind( &Foo::Ptr::get, 
                                            bll::_1         ))) (bll::_1) == 2);

, где

bll::bind( &Foo::Ptr::get, bll::_1)

Вытягивает указатель, чтобы заполнитель не разыскивался в строке.

Из комментариев, предлагающих безошибочную компиляцию в VS с Boost 1_47, я могу предположить, что с тех пор проблема была исправлена ​​в boost, и это была своего рода ошибка.

1 голос
/ 27 июля 2011

Как вы обнаружили, вы не можете этого сделать, потому что объект должен быть скопирован, но в этом случае его нельзя создать, поскольку он содержит чисто виртуальный метод.Самое простое решение - передать его с помощью указателя:

#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;
}

Чтобы быть более точным, это:

*bll::_1

необходимо создать экземпляр объекта типа CopyFoo

...