3

I'm trying to chain together curried functions using boost::bind, and getting compiler errors that I can't resolve. The simplest example I can make which fails to compile:

#include <iostream>
#include <boost/bind.hpp>

class A
{
public:
    template <typename F>
    void g(F fn, char c)
    {
        fn(c);
    }

    void h(char c)
    {
        std::cout << c << std::endl;
    }

    template <typename F>
    void f(F fn, char c)
    {
        boost::bind(&A::g<F>, this, fn, ::_1)(c);
    }
};

int main(int argc, char** argv)
{
    char c = 'a';
    A a;
    a.f(boost::bind(&A::h, &a, ::_1), c);
}

fails with this error:

In file included from /usr/include/boost/bind.hpp:22,
                 from test8.cpp:2:
/usr/include/boost/bind/bind.hpp: In member function ‘void boost::_bi::list3<A1, A2, A3>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = boost::_mfi::mf2<void, A, boost::_bi::bind_t<void, boost::_mfi::mf1<void, A, char>, boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> > >, char>, A = boost::_bi::list1<char&>, A1 = boost::_bi::value<A*>, A2 = boost::_bi::bind_t<void, boost::_mfi::mf1<void, A, char>, boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> > >, A3 = boost::arg<1>]’:
/usr/include/boost/bind/bind_template.hpp:32:   instantiated from ‘typename boost::_bi::result_traits<R, F>::type boost::_bi::bind_t<R, F, L>::operator()(A1&) [with A1 = char, R = void, F = boost::_mfi::mf2<void, A, boost::_bi::bind_t<void, boost::_mfi::mf1<void, A, char>, boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> > >, char>, L = boost::_bi::list3<boost::_bi::value<A*>, boost::_bi::bind_t<void, boost::_mfi::mf1<void, A, char>, boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> > >, boost::arg<1> >]’
test8.cpp:21:   instantiated from ‘void A::f(F, char) [with F = boost::_bi::bind_t<void, boost::_mfi::mf1<void, A, char>, boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> > >]’
test8.cpp:29:   instantiated from here
/usr/include/boost/bind/bind.hpp:385: error: invalid use of void expression

This is using

$ g++ --version
g++ (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3
NNN
  • 386
  • 1
  • 9
  • 4
    Be aware of that when you pass the result of a boost::bind to another boost::bind, it will call it rather than to pass it along as a parameter. To prevent it from being called, wrap it in boost::protect() – PlasmaHH Oct 02 '12 at 11:19

1 Answers1

6

You need to use boost::protect() in such cases, when you pass a bind expression to another bind call but don't want the nested one to be invoked during the evaluation of arguments to the outer bound function, but rather want the nested bind expression to be passed as-is as an argument to the outer bound function. Here it will be:

boost::bind(&A::g<F>, this, boost::protect(fn), ::_1)(c);
usta
  • 6,699
  • 3
  • 22
  • 39
  • That fixed it, thanks! I wasn't aware of boost::protect. Docs are here for future reference: http://www.boost.org/doc/libs/1_51_0/libs/bind/bind.html#nested_binds – NNN Oct 02 '12 at 11:27