2

I'm trying to generate a periodic timer class using the boost.asio library. However, I get "invalid use of non-static member function" errors. The cpp file is as the following:

#include "TimerBoost.h"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <chrono>
#include <string>
using namespace std;
boost::asio::io_context io;

TimerBoost::TimerBoost(int timerSec)
{
    setParam(timerSec); //timerSec is the desired period of the timer in terms of second
    boost::asio::steady_timer tim{io, std::chrono::seconds{tSec}};
    tim.async_wait(boost::bind(print, &tim, &tSec));
    io.run();
}
TimerBoost::TimerBoost()
{
    setParam(5);
    boost::asio::steady_timer tim{io, std::chrono::seconds{tSec}};
    tim.async_wait(boost::bind(print, &tim, &tSec));
    io.run();
}
void TimerBoost::setParam(int timerSec)
{
    tSec=timerSec;
}
void TimerBoost::print(boost::asio::steady_timer* tim, int* tSec)
{
    tim->expires_from_now(boost::asio::chrono::seconds(*tSec));
    tim->async_wait(boost::bind(print, tim, tSec));
}

The header file is as the following:

#include <string>
#include <boost/asio/io_context.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <chrono>
#include <iostream>
#ifndef TIMERBOOST_H_
#define TIMERBOOST_H_

using namespace std;

class TimerBoost {
public:
    TimerBoost(int tSec);
    TimerBoost();
    void setParam(int tSec);
    void print(boost::asio::steady_timer* tim, int* tSec);

private:
    int tSec;
};
#endif /* TIMERBOOST_H_ */

When I build the project, I get 3 errors which are:

  1. error: invalid use of non-static member function

    tim.async_wait(boost::bind(print, &tim, &tSec));

  2. error: invalid use of non-static member function

    tim.async_wait(boost::bind(print, &tim, &tSec));

  3. error: invalid use of non-static member function

    tim->async_wait(boost::bind(print, tim, tSec));

Do you know the solution of the errors? Thanks!

1 Answers1

2

You have two problems:

The first is that non-static member function needs an object to be called on. This is usually passed as a hidden first argument. You solve this by passing this as the first argument to the member-function you want to call.

The second problem is that you need to use explicit pointers to member functions. This is done by fully scoping it and using the address-of operator &.

So the working bind call should look something like:

boost::bind(&TimerBoost::print, this, &tim, &tSec)

Another possible solution, that is usually preferred over "binding", is to use lambdas:

tim.async_wait([tim, tSec, this]()
{
    print(&tim, &tSec);
});
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • @AnılÇavuşoğlu Forgot one thing, added it now – Some programmer dude Nov 07 '18 at 11:26
  • 2
    A risk carried by acting FGITW. – StoryTeller - Unslander Monica Nov 07 '18 at 11:26
  • The author declares the `boost::asio::steady_timer` right in constructor, which will be destroyed on constructor exit. Shouldn't we declare the timer as class member or keep it alive in some other way (e.g. `shared_ptr` ) to make it work? – Oleh Zaiats Feb 17 '23 at 10:23
  • 1
    @OlehZaiats [The `run` function](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/io_context/run/overload1.html) prevents the constructor function from returning until the "work" has finished, which in this case is when the timer have expired. Is it a good idea to do that in a constructor? No, but at least the timer will be kept alive. – Some programmer dude Feb 17 '23 at 10:29
  • ahhh, I see :) So assuming the `io_service.run()` is moved to a separate thread, if the `Timer` constructor exited and `boost::asio::steady_timer` was destroyed - that would lead to undefined behavior. – Oleh Zaiats Feb 17 '23 at 10:58