boost::deadline_timer error: static assertion failed: WaitHandler type requirements not met

I have a cnx class which represents a socket and it must also has a timer in which if the clients stays more than cnx::timeout_mili milliseconds without responding then I’ll close the connection. Each timer will start when the connection is made, or, when the cnx object is instantiated. The socket part is working fine, now when I try to add the timer to the cnx class its build fails with the following errors:

In file included from /home/pcuser/src/boost_1_71_0/boost/asio/impl/execution_context.hpp:18,
                 from /home/pcuser/src/boost_1_71_0/boost/asio/execution_context.hpp:409,
                 from /home/pcuser/src/boost_1_71_0/boost/asio/detail/scheduler.hpp:21,
                 from /home/pcuser/src/boost_1_71_0/boost/asio/system_context.hpp:19,
                 from /home/pcuser/src/boost_1_71_0/boost/asio/impl/system_executor.hpp:22,
                 from /home/pcuser/src/boost_1_71_0/boost/asio/system_executor.hpp:129,
                 from /home/pcuser/src/boost_1_71_0/boost/asio/associated_executor.hpp:21,
                 from /home/pcuser/src/boost_1_71_0/boost/asio.hpp:21,
                 from /home/pcuser/src/cpp-server/comum.h:9,
                 from /home/pcuser/src/cpp-server/cnx.h:4,
                 from /home/pcuser/src/cpp-server/cnx.cpp:1:
/home/pcuser/src/boost_1_71_0/boost/asio/basic_deadline_timer.hpp: In instantiation of ‘void boost::asio::basic_deadline_timer<Time, TimeTraits, Executor>::initiate_async_wait::operator()(WaitHandler&&, boost::asio::basic_deadline_timer<Time, TimeTraits, Executor>*) const [with WaitHandler = void (cnx::*)(const boost::system::error_code&); Time = boost::posix_time::ptime; TimeTraits = boost::asio::time_traits<boost::posix_time::ptime>; Executor = boost::asio::executor]’:
/home/pcuser/src/boost_1_71_0/boost/asio/async_result.hpp:82:49:   required from ‘static boost::asio::async_result<CompletionToken, Signature>::return_type boost::asio::async_result<CompletionToken, Signature>::initiate(Initiation&&, RawCompletionToken&&, Args&& ...) [with Initiation = boost::asio::basic_deadline_timer<boost::posix_time::ptime>::initiate_async_wait; RawCompletionToken = void (cnx::*)(const boost::system::error_code&); Args = {boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::executor>*}; CompletionToken = void (cnx::*)(const boost::system::error_code&); Signature = void(boost::system::error_code); boost::asio::async_result<CompletionToken, Signature>::return_type = void]’
/home/pcuser/src/boost_1_71_0/boost/asio/async_result.hpp:257:25:   required from ‘typename std::enable_if<boost::asio::detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value, typename boost::asio::async_result<typename std::decay<_Tp>::type, Signature>::return_type>::type boost::asio::async_initiate(Initiation&&, CompletionToken&, Args&& ...) [with CompletionToken = void (cnx::*)(const boost::system::error_code&); Signature = void(boost::system::error_code); Initiation = boost::asio::basic_deadline_timer<boost::posix_time::ptime>::initiate_async_wait; Args = {boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::executor>*}; typename std::enable_if<boost::asio::detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value, typename boost::asio::async_result<typename std::decay<_Tp>::type, Signature>::return_type>::type = void; typename boost::asio::async_result<typename std::decay<_Tp>::type, Signature>::return_type = void; typename std::decay<_Tp>::type = void (cnx::*)(const boost::system::error_code&)]’
/home/pcuser/src/boost_1_71_0/boost/asio/basic_deadline_timer.hpp:629:73:   required from ‘typename boost::asio::async_result<typename std::decay<_Functor>::type, void(boost::system::error_code)>::return_type boost::asio::basic_deadline_timer<Time, TimeTraits, Executor>::async_wait(WaitHandler&&) [with WaitHandler = void (cnx::*)(const boost::system::error_code&); Time = boost::posix_time::ptime; TimeTraits = boost::asio::time_traits<boost::posix_time::ptime>; Executor = boost::asio::executor; typename boost::asio::async_result<typename std::decay<_Functor>::type, void(boost::system::error_code)>::return_type = void; typename std::decay<_Functor>::type = void (cnx::*)(const boost::system::error_code&)]’
/home/pcuser/src/cpp-server/cnx.cpp:15:25:   required from here
/home/pcuser/src/boost_1_71_0/boost/asio/detail/handler_type_requirements.hpp:376:62: error: static assertion failed: WaitHandler type requirements not met
  373 |       sizeof(boost::asio::detail::one_arg_handler_test( 
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     
  374 |           boost::asio::detail::rvref< 
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                       
  375 |             asio_true_handler_type>(), 
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~                      
  376 |           static_cast<const boost::system::error_code*>(0))) == 1, 
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/home/pcuser/src/boost_1_71_0/boost/asio/detail/handler_type_requirements.hpp:105:20: note: in definition of macro ‘BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT’
  105 |      static_assert(expr, msg);
      |                    ^~~~
/home/pcuser/src/boost_1_71_0/boost/asio/basic_deadline_timer.hpp:647:7: note: in expansion of macro ‘BOOST_ASIO_WAIT_HANDLER_CHECK’
  647 |       BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/pcuser/src/boost_1_71_0/boost/asio/detail/handler_type_requirements.hpp:376:62: note: ‘(sizeof (boost::asio::detail::one_arg_handler_test<void (cnx::*)(const boost::system::error_code&)>(boost::asio::detail::rvref<void (cnx::*)(const boost::system::error_code&)>(), 0)) == 1)’ evaluates to false
  373 |       sizeof(boost::asio::detail::one_arg_handler_test( 
      |       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~     
  374 |           boost::asio::detail::rvref< 
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                       
  375 |             asio_true_handler_type>(), 
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~                      
  376 |           static_cast<const boost::system::error_code*>(0))) == 1, 
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/home/pcuser/src/boost_1_71_0/boost/asio/detail/handler_type_requirements.hpp:105:20: note: in definition of macro ‘BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT’
  105 |      static_assert(expr, msg);
      |                    ^~~~
/home/pcuser/src/boost_1_71_0/boost/asio/basic_deadline_timer.hpp:647:7: note: in expansion of macro ‘BOOST_ASIO_WAIT_HANDLER_CHECK’
  647 |       BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/pcuser/src/boost_1_71_0/boost/asio/detail/handler_type_requirements.hpp:280:36: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘boost::asio::detail::lvref<void (cnx::*)(const boost::system::error_code&)>() (...)’, e.g. ‘(... ->* boost::asio::detail::lvref<void (cnx::*)(const boost::system::error_code&)>()) (...)’
  279 |         boost::asio::detail::lvref< 
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  280 |           asio_true_handler_type>()( 
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~^~~
  281 |             boost::asio::detail::lvref<const boost::system::error_code>()), 
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/pcuser/src/boost_1_71_0/boost/asio/basic_socket.hpp:1817:7: note: in expansion of macro ‘BOOST_ASIO_CONNECT_HANDLER_CHECK’
 1817 |       BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/Server.dir/build.make:90: CMakeFiles/Server.dir/cnx.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....


make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/Server.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

My code is the following:

cnx.h

#ifndef CNX_H
#define CNX_H

#include <boost/asio.hpp>
using boost::asio::ip::tcp;

typedef boost::asio::io_service ioservice;

using namespace std;
class cnx
{
public:
    inline static int timeout_mili = 10000;
    cnx(ioservice& io);
    void timer_counter_reset();
    bool conectado;

private:
    tcp::socket s;
    boost::asio::io_service timer_io;
    boost::asio::deadline_timer cnx_timer;

    void timer_ended(const boost::system::error_code& e);
};

#endif // CNX_H

cnx.cpp

#include "cnx.h"

cnx::cnx(ioservice& io) :
    s(tcp::socket(io)),
    conectado(false),
    cnx_timer(boost::asio::deadline_timer(timer_io, boost::posix_time::milliseconds(cnx::timeout_mili)))
{
    timer_io.run();

    cnx_timer.async_wait(&cnx::timer_ended);
}

// I'll call this outsite so the timer gets reset and restart couting
void cnx::timer_counter_reset()
{
    cnx_timer.cancel();
    cnx_timer.async_wait(&cnx::timer_ended);
}

void cnx::timer_ended(const boost::system::error_code& e)
{
    if(e){
        cout << "cnx id " << id << " resetted timer" << endl;
        return;
    }
    this->conectado = false;
}

I don’t know exactly what I’m doing wrong on the functions signatures. Also my question doesn’t seems to be already answered here. Thanks in advance.

EDIT So, it seems the problem is when referencing the method &cnx::timer_ended in async_wait calls, I added a test function in cnx.h like this:

inline static void testtt(const boost::system::error_code& e)
{
    cout << "testtt" << endl;
    return;
}

and changed the async_await calls from cnx_timer.async_wait(&cnx::timer_ended); to cnx_timer.async_wait(cnx::testtt);

and it worked. However I still don’t know how to solve it because I need to change a value per instance of cnx objects so I can’t use a static function… any ideas?

EDIT 2 Even now when it’s compiling, the code is not working as expected, the function “testtt” is not being fired at all.

Answer

This is the classical “problem” of binding member functions. For member functions you also need to have a “this value”, where will that come from?

There are roughly two appraoches:

  • bind
  • lambda

Bind

Using e.g. boost::bind you can

cnx_timer.async_wait(boost::bind(&cnx::timer_ended, this,
                                 boost::asio::placeholders::error()));

Now the callback is bound to this. Keep in mind that you have to make sure that the cnx object stays valid. Also keep in mind thread safety.

Side note;

// I'll call this outsite so the timer gets reset and restart couting
void cnx::timer_counter_reset()
{
    cnx_timer.cancel();

That doesn’t reset the timer. It merely cancels any pending async wait. To actually reset it, use expires_from_now or expires_at again.