2012-05-15 8 views
12

Acabo de escribir un ejemplo simple para probar boost :: bind. Lo uso para instanciar una función de miembro de plantilla, pero no compilará con g ++ 4.6.0. No sé cuál es el problema. Aquí está el código:boost :: bind no compila con la función de plantilla de miembro

#include <boost/bind.hpp> 

struct Functor 
{ 
    void operator()() 
    { 

    } 
}; 

struct DerivedFinishAction 
{ 
    DerivedFinishAction() 
    {} 

    void Inc() 
    { 

    } 

    template <typename T> 
    void TmplFunc(T t) 
    { 
    (boost::bind(&DerivedFinishAction::BindFunc<T>, this , t))(); 
    } 

    template <typename T> 
    void BindFunc(T t) 
    { 
    t(); 
    } 

    void Func() 
    { 
    Functor f; 
    TmplFunc(f); // this is OK 
    TmplFunc(boost::bind(&DerivedFinishAction::Inc, this)); // compile error 
    } 
}; 

int main(int argc, char *argv[]) 
{ 

    return 0; 
} 

y G ++ da los siguientes errores:

In file included from /usr/include/boost/bind.hpp:22:0, 
       from testBind.cpp:1: 
/usr/include/boost/bind/bind.hpp: In member function ‘void boost::_bi::list2<A1, A2>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = boost::_mfi::mf1<void, DerivedFinishAction, boost::_bi::bind_t<void, boost::_mfi::mf0<void, DerivedFinishAction>, boost::_bi::list1<boost::_bi::value<DerivedFinishAction*> > > >, A = boost::_bi::list0, A1 = boost::_bi::value<DerivedFinishAction*>, A2 = boost::_bi::bind_t<void, boost::_mfi::mf0<void, DerivedFinishAction>, boost::_bi::list1<boost::_bi::value<DerivedFinishAction*> > >]’: 
/usr/include/boost/bind/bind_template.hpp:20:59: instantiated from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()() [with R = void, F = boost::_mfi::mf1<void, DerivedFinishAction, boost::_bi::bind_t<void, boost::_mfi::mf0<void, DerivedFinishAction>, boost::_bi::list1<boost::_bi::value<DerivedFinishAction*> > > >, L = boost::_bi::list2<boost::_bi::value<DerivedFinishAction*>, boost::_bi::bind_t<void, boost::_mfi::mf0<void, DerivedFinishAction>, boost::_bi::list1<boost::_bi::value<DerivedFinishAction*> > > >, boost::_bi::bind_t<R, F, L>::result_type = void]’ 
testBind.cpp:24:5: instantiated from ‘void DerivedFinishAction::TmplFunc(T) [with T = boost::_bi::bind_t<void, boost::_mfi::mf0<void, DerivedFinishAction>, boost::_bi::list1<boost::_bi::value<DerivedFinishAction*> > >]’ 
testBind.cpp:37:58: instantiated from here 
/usr/include/boost/bind/bind.hpp:313:9: error: invalid use of void expression 

¿Alguien puede ayudar a explicar esto? ¿Por qué la primera instanciación está bien mientras que la segunda causa un error de compilación?

+1

Esto es raro .. –

+0

@SethCarnegie, 15 minutos, solo para eso XD – chris

Respuesta

13

Hay una característica (no obvia) de boost::bind implicada aquí. http://www.boost.org/libs/bind/#nested_binds

si escribe:

void func1(int len) {return len+1;}; 
int func2(std::string str) {return str.length();}; 

assert(
    boost::bind(func1, boost::bind(func2, _1))("Hello") 
    == 6); 

boost::bind supone que lo que quiere decir es "ejecutar func2 en "Hello", a continuación, ejecute func1 en el resultado". Esto permite una aplicación de función parcial más interesante.

En su programa, que tiene una expresión que equivale a:

boost::bind(&DerivedFinishAction::BindFunc<...>, 
      this, 
      boost::bind(&DerivedFinishAction::Inc, this)) 

Así boost::bind intentos para averiguar cómo ejecutar DerivedFinishAction::Inc en ella argumentos, por lo que puede pasar ese resultado en DerivedFinishAction::BindFunc<...>. Pero DerivedFinishAction::Inc devuelve nulo, que no se puede pasar al DerivedFinishAction::BindFunc<...>. De este modo se obtiene un error de compilación:

/usr/include/boost/bind/bind.hpp:313:9: error: invalid use of void expression 

Editar: Por la documentación, puede utilizar protect para lograr su comportamiento deseado:

#include <boost/bind/protect.hpp> 
... 
TmplFunc(boost::protect(boost::bind(&DerivedFinishedAction::Inc, this))); // no longer an error 
... 
+0

Esta característica de 'boost :: bind' también se aplica a' std :: bind'. – ildjarn

+0

La solución es genial. Gracias @Managu – airekans

Cuestiones relacionadas