2

I was making some modifications to a boost::asio project today and I ran into a confusing compilation error when attempting to pass a bound function into an async call.

I have spent hours fiddling with this code, so I suspect I am missing something stupid. I would appreciate anyone who can point out where I am going wrong.

error: no match for call to ‘(boost::_mfi::mf3<void, ClientServerManager, 
    const MCServer&, boost::shared_ptr<Connection>, 
    const boost::system::error_code&>) (ClientServerManager*&, 
    MCServer&, boost::shared_ptr<Connection>&, 
    const MCServer&)’

Notice that const MCServer& appears twice? That isn't how my bind statement is written:

void ClientServerManager::onConnect(const MCServer& server_info, 
    boost::shared_ptr<Connection> con,
    const boost::system::error_code& err,
    tcp::resolver::iterator i) {

    // Instruct utility to do some work, and call our function when complete.
    con->statusPing(
        boost::bind( // <-- OFFENDING CODE
            &ClientServerManager::onPingCompletion,
            this,
            server_info,
            con,  // shared_ptr to connection (maintains scope)
            boost::asio::placeholders::error // in case of a downstream failure
        )
    );
}

In the Connection header statusPing(...) is defined as follows:

void statusPing(boost::function<
    void(
        MCServer&, boost::shared_ptr<Connection>, 
        const boost::system::error_code&
    )>);

The handler eventually to be called:

void ClientServerManager::onPingCompletion(
    const MCServer& server_info, 
    boost::shared_ptr<Connection>,     
    const boost::system::error_code& err){
    // Use the results to drive some function...
}

Background:

  • I have a class which iterates through a list of servers and opens short-lived connections with them to make sure they are operating properly.
  • The class uses a utility, Connection which inherits boost::enable_shared_from_this. Therefore, I call a function, Connection::create(..) to grab a boost::shared_ptr to start work with. When any async calls are made, this pointer has to be passed to keep the connection in scope.
  • In this instance after the connection is successfully established, I want to pass execution to Connection such that it can execute some tasks, and I want it to call a handle once those tasks are complete. I cannot get boost::bind to compile properly in this case.
  • Now the issue I am having is that the boost::bind might be linked to the use of the boost::asio::placeholders::error template.

The full output follows:

   g++ -std=c++0x -DBOOST_LOG_DYN_LINK -I/home/donald/Desktop/workspace/MCProxy/Debug/ -O3 -march=corei7-avx -g1 -w -c -fmessage-length=0 -MMD -MP -MF"src/ClientServerManager.d" -MT"src/ClientServerManager.d" -o "src/ClientServerManager.o" "../src/ClientServerManager.cpp"
In file included from ....
/boost/bind/bind.hpp: In instantiation of ‘void boost::_bi::list4<A1, A2, A3, A4>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>; A = boost::_bi::list3<const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>; A1 = boost::_bi::value<ClientServerManager*>; A2 = boost::_bi::value<MCServer>; A3 = boost::_bi::value<boost::shared_ptr<Connection> >; A4 = boost::arg<1> (*)()]’:
/boost/bind/bind_template.hpp:116:59:   required from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()(A1&, A2&, A3&) [with A1 = const MCServer; A2 = boost::shared_ptr<Connection>; A3 = const boost::system::error_code; R = void; F = boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>; L = boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()>; boost::_bi::bind_t<R, F, L>::result_type = void]’
/boost/function/function_template.hpp:153:11:   required from ‘static void boost::detail::function::void_function_obj_invoker3<FunctionObj, R, T0, T1, T2>::invoke(boost::detail::function::function_buffer&, T0, T1, T2) [with FunctionObj = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void; T0 = const MCServer&; T1 = boost::shared_ptr<Connection>; T2 = const boost::system::error_code&]’
/boost/function/function_template.hpp:934:60:   required from ‘void boost::function3<R, T1, T2, T3>::assign_to(Functor) [with Functor = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void; T0 = const MCServer&; T1 = boost::shared_ptr<Connection>; T2 = const boost::system::error_code&]’
/boost/function/function_template.hpp:722:7:   required from ‘boost::function3<R, T1, T2, T3>::function3(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void; T0 = const MCServer&; T1 = boost::shared_ptr<Connection>; T2 = const boost::system::error_code&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/boost/function/function_template.hpp:1071:16:   required from ‘boost::function<R(T0, T1, T2)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void; T0 = const MCServer&; T1 = boost::shared_ptr<Connection>; T2 = const boost::system::error_code&; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
../src/ClientServerManager.cpp:90:3:   required from here
/boost/bind/bind.hpp:457:9: error: no match for call to ‘(boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>, const boost::system::error_code&>) (ClientServerManager*&, MCServer&, boost::shared_ptr<Connection>&, const MCServer&)’
In file included ....
/boost/bind/mem_fn_template.hpp:366:85: note: candidates are:
/boost/bind/mem_fn_template.hpp:391:7: note: R boost::_mfi::mf3<R, T, A1, A2, A3>::operator()(T*, A1, A2, A3) const [with R = void; T = ClientServerManager; A1 = const MCServer&; A2 = boost::shared_ptr<Connection>; A3 = const boost::system::error_code&]
/boost/bind/mem_fn_template.hpp:391:7: note:   no known conversion for argument 4 from ‘const MCServer’ to ‘const boost::system::error_code&’
/boost/bind/mem_fn_template.hpp:396:25: note: template<class U> R boost::_mfi::mf3::operator()(U&, A1, A2, A3) const [with U = U; R = void; T = ClientServerManager; A1 = const MCServer&; A2 = boost::shared_ptr<Connection>; A3 = const boost::system::error_code&]
/boost/bind/mem_fn_template.hpp:396:25: note:   template argument deduction/substitution failed:
In file included ....
/boost/bind/bind.hpp:457:9: note:   cannot convert ‘(& a)->boost::_bi::list3<A1, A2, A3>::operator[]<const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>(boost::_bi::storage4<A1, A2, A3, boost::arg<I> (*)()>::a4_<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, 1>)’ (type ‘const MCServer’) to type ‘const boost::system::error_code&’
In file included ....
/boost/bind/mem_fn_template.hpp:404:25: note: template<class U> R boost::_mfi::mf3::operator()(const U&, A1, A2, A3) const [with U = U; R = void; T = ClientServerManager; A1 = const MCServer&; A2 = boost::shared_ptr<Connection>; A3 = const boost::system::error_code&]
/boost/bind/mem_fn_template.hpp:404:25: note:   template argument deduction/substitution failed:
In file included ....
/boost/bind/bind.hpp:457:9: note:   cannot convert ‘(& a)->boost::_bi::list3<A1, A2, A3>::operator[]<const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>(boost::_bi::storage4<A1, A2, A3, boost::arg<I> (*)()>::a4_<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, 1>)’ (type ‘const MCServer’) to type ‘const boost::system::error_code&’
In file included from ....
/boost/bind/mem_fn_template.hpp:412:7: note: R boost::_mfi::mf3<R, T, A1, A2, A3>::operator()(T&, A1, A2, A3) const [with R = void; T = ClientServerManager; A1 = const MCServer&; A2 = boost::shared_ptr<Connection>; A3 = const boost::system::error_code&]
/boost/bind/mem_fn_template.hpp:412:7: note:   no known conversion for argument 1 from ‘ClientServerManager*’ to ‘ClientServerManager&’

Edit: (boost::function<void(...)> -> boost::function<void()>)

Per suggestion, I changed the Connection function to read void statusPing(boost::function<void()>); as the parameters are bound in. This change yields a different error:

g++ -std=c++0x -DBOOST_LOG_DYN_LINK -I/home/donald/Desktop/workspace/MCProxy/Debug/ -O3 -march=corei7-avx -g1 -w -c -fmessage-length=0 -MMD -MP -MF"src/ClientServerManager.d" -MT"src/ClientServerManager.d" -o "src/ClientServerManager.o" "../src/ClientServerManager.cpp"
In file included from ....
/boost/bind/bind.hpp: In instantiation of ‘void boost::_bi::list4<A1, A2, A3, A4>::operator()(boost::_bi::type<void>, F&, A&, int) [with F = boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>; A = boost::_bi::list0; A1 = boost::_bi::value<ClientServerManager*>; A2 = boost::_bi::value<MCServer>; A3 = boost::_bi::value<boost::shared_ptr<Connection> >; A4 = boost::arg<1> (*)()]’:
/boost/bind/bind_template.hpp:20:59:   required from ‘boost::_bi::bind_t<R, F, L>::result_type boost::_bi::bind_t<R, F, L>::operator()() [with R = void; F = boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>; L = boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()>; boost::_bi::bind_t<R, F, L>::result_type = void]’
/boost/function/function_template.hpp:153:11:   required from ‘static void boost::detail::function::void_function_obj_invoker0<FunctionObj, R>::invoke(boost::detail::function::function_buffer&) [with FunctionObj = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void]’
/boost/function/function_template.hpp:934:60:   required from ‘void boost::function0<R>::assign_to(Functor) [with Functor = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void]’
/boost/function/function_template.hpp:722:7:   required from ‘boost::function0<R>::function0(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/boost/function/function_template.hpp:1071:16:   required from ‘boost::function<R()>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::_bi::bind_t<void, boost::_mfi::mf3<void, ClientServerManager, const MCServer&, boost::shared_ptr<Connection>&, const boost::system::error_code&>, boost::_bi::list4<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, boost::arg<1> (*)()> >; R = void; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
../src/ClientServerManager.cpp:90:2:   required from here
/boost/bind/bind.hpp:457:9: error: no match for ‘operator[]’ in ‘a[boost::_bi::storage4<A1, A2, A3, boost::arg<I> (*)()>::a4_<boost::_bi::value<ClientServerManager*>, boost::_bi::value<MCServer>, boost::_bi::value<boost::shared_ptr<Connection> >, 1>]’
/boost/bind/bind.hpp:457:9: note: candidates are:
In file included ....
/boost/bind/bind.hpp:170:27: note: template<class T> T& boost::_bi::list0::operator[](boost::_bi::value<T>&) const
/boost/bind/bind.hpp:170:27: note:   template argument deduction/substitution failed:
In file included ....
/boost/bind/bind.hpp:457:9: note:   mismatched types ‘boost::_bi::value<T>’ and ‘boost::arg<1>()’
In file included ....
/boost/bind/bind.hpp:172:33: note: template<class T> const T& boost::_bi::list0::operator[](const boost::_bi::value<T>&) const
/boost/bind/bind.hpp:172:33: note:   template argument deduction/substitution failed:
In file included ....
/boost/bind/bind.hpp:457:9: note:   mismatched types ‘const boost::_bi::value<T>’ and ‘boost::arg<1>()’
In file included ....
/boost/bind/bind.hpp:174:27: note: template<class T> T& boost::_bi::list0::operator[](const boost::reference_wrapper<T>&) const
/boost/bind/bind.hpp:174:27: note:   template argument deduction/substitution failed:
In file included from ....
/boost/bind/bind.hpp:457:9: note:   mismatched types ‘const boost::reference_wrapper<T>’ and ‘boost::arg<1>()’
In file included from ....
/boost/bind/bind.hpp:176:76: note: template<class R, class F, class L> typename boost::_bi::result_traits<R, F>::type boost::_bi::list0::operator[](boost::_bi::bind_t<R, F, L>&) const
/boost/bind/bind.hpp:176:76: note:   template argument deduction/substitution failed:
In file included from ....
/boost/bind/bind.hpp:457:9: note:   mismatched types ‘boost::_bi::bind_t<R, F, L>’ and ‘boost::arg<1>()’
/boost/bind/bind.hpp:178:76: note: template<class R, class F, class L> typename boost::_bi::result_traits<R, F>::type boost::_bi::list0::operator[](const boost::_bi::bind_t<R, F, L>&) const
/boost/bind/bind.hpp:178:76: note:   template argument deduction/substitution failed:
/boost/bind/bind.hpp:457:9: note:   mismatched types ‘const boost::_bi::bind_t<R, F, L>’ and ‘boost::arg<1>()’
make: *** [src/ClientServerManager.o] Error 1

A simplified example:

#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <boost/function.hpp>

class ExampleWorker {
    public:
        void statusPing(boost::function<void()> f){
            // Do work.
            f(); // Call handle
        }
};

class SomeObject {};

void someHandle(boost::shared_ptr<SomeObject> obj,
        const boost::system::error_code& err){
    // ...
}

int main() {
    ExampleWorker* e = new ExampleWorker();
    boost::shared_ptr<SomeObject> ptr(new SomeObject());

    e->statusPing(
            boost::bind(
                &someHandle,
                ptr,
                boost::asio::placeholders::error
            )
    );
}
Don Scott
  • 3,179
  • 1
  • 26
  • 40
  • 1
    You're binding all the arguments necessary for invoking `ClientServerManager::onPingCompletion()`, so the callable created from the bind expression will convert to a `boost::function`. Try making that change to `statusPing()`, and your code should compile. – Praetorian Dec 22 '14 at 06:16
  • Also, those are all compiler errors, not linker errors. Your question is a little confusing at first because you keep mentioning link and linkage errors. – Praetorian Dec 22 '14 at 06:20
  • Thank you @Praetorian for that guidance. I am still getting an error; would you have any additional advice? `error: no match for ‘operator[]’ in ‘a[boost::_bi::storage4 (*)()>::a4_, boost::_bi::value, boost::_bi::value >, 1>]’` – Don Scott Dec 22 '14 at 06:47
  • Could you show the updated code? Note that either `statusPing` must accept `function`, or you should create a binder that accepts 3 parameters, like `bind(this, _1, _2, _3)` - depending on how you actually intend to invoke that functor. – Igor R. Dec 22 '14 at 13:57
  • 1
    Is it the same line that's causing the new error? Can you please try to create an [SSCCE](http://sscce.org) that reproduces the issue? – Praetorian Dec 22 '14 at 17:57
  • @Praetorian Yes, it appears so. Take a look at the simplified example I posted. What silly error am I making? – Don Scott Dec 25 '14 at 05:28
  • Hi, I posted an answer explaining the problem in your simplified example. I know it doesn't solve your original problem, but I'm having trouble understanding the chain of function calls happening in there. Is `onConnect` the asio completion handler function, and you want to pass the error code that the asio operation called `onConnect` with to `statusPing`, and then onto `onPingCompletion`? And I apologize for misleading you earlier, I missed that you were passing `boost::asio::placeholders::error` in the bind arguments. – Praetorian Dec 27 '14 at 07:02

1 Answers1

1

boost::asio::placeholders::error is just like using boost::placeholders::_1 with boost::bind, and when you pass a bind expression containing that to an asio completion handler function, the function will invoke your handler with the boost::system::error_code result from the operation it performed, thus allowing your handler access to the error code.

In your second example, the boost::function signature for the following bind expression

boost::bind(
    &someHandle,
    ptr,
    boost::asio::placeholders::error
)

is

boost::function<void(boost::system::error_code const&)>

To get your code to compile, change the statusPing() member function to

void statusPing(boost::function<void(boost::system::error_code const&)> f){
    // Do work.
    boost::system::error_code err;
    f(err); // Call handle
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • Thank you, that is exactly correct. I discovered my error after reading more about `boost::bind` last night. I found http://stackoverflow.com/questions/527413/how-boostfunction-and-boostbind-work and http://www.radmangames.com/programming/how-to-use-boost-bind to be good resources. – Don Scott Dec 27 '14 at 18:41