ArctiC
ArctiC

Reputation: 3

Cant call function reference c++

I got this function which needs function reference:

template <typename Fn>
void Caller::operator()(const Fn& funct, bool*is_running, int time_sec)
{
    //Some code
    funct();

}

And i call it like that:

auto t = make_timer(DataHandler::dh().send, Data::sendPeriod);

Send function is in DataHandler class, i use a static instance of dh:

static DataHandler& dh(){static DataHandler dh = DataHandler(); return dh;}

It returns error:

error: must use '.*' or '->*' to call pointer-to-member function in 'funct (...)', e.g. '(...->* funct) (...)'

It says it is required from main where i call it.

Anyone knows what the problem might be?

Minimal, Complete, and Verifiable Example:

#include <iostream>

#include "timer.h"

class DataHandler{
public:
    static DataHandler& dh(){static DataHandler dh = DataHandler(); return dh;}
    DataHandler(){};
    void send(){std::cout << "send";}
};

int main()
{
    auto t = make_timer(DataHandler::dh().send, 20);

    return 0;
}

And timer.h although i dont know how to shorten it :(

#include <thread>
#include <functional>


struct Caller
{

    template<typename Fn>
    void operator()(const Fn& funct, bool*is_running, int time_sec);
};


template <typename Fn>
class Timer
{
protected:
    std::thread  timer_thread;
    bool    is_running;

public:
    Timer(Fn fn, int time_sec);
    Timer(const Timer&) = delete;
    Timer(Timer&& timer);


    void stop();

    ~Timer();
};




    template <typename Fn>
    void Caller::operator()(const Fn& funct, bool*is_running, int time_sec)
    {
        do
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(time_sec*1000));
            funct();

        } while(*is_running);

    }



    template <typename Fn>
    Timer<Fn>::Timer(Fn fn, int time_sec)
    :
    is_running(true)
    {
        Caller caller{};
        auto proc = std::bind(caller, fn, &(this->is_running), time_sec);
        std::thread tmp(proc);
        swap(this->timer_thread, tmp);
    }

    template <typename Fn>
    Timer<Fn>::Timer(Timer&& timer)
    :
    timer_thread(move(timer.timer_thread)),
    is_running(timer.is_running)
    {
    }

    template <typename Fn>
    void Timer<Fn>::stop()
    {
        if(this->is_running)
            this->is_running = false;
    }

    template <typename Fn>
    Timer<Fn>::~Timer()
    {
        //this->stop();
        timer_thread.join();
    }

template<typename Fn>
Timer<Fn> make_timer(Fn fn, int time)
{
    return Timer<Fn>{fn, time};
}

Upvotes: 0

Views: 115

Answers (1)

Some programmer dude
Some programmer dude

Reputation: 409136

That's not how to pass non-static member functions as a callback.

First of all, you need to use the address-of operator to get a pointer to a member function. Secondly, you need an object instance for the function to be called with, and this is kind of passed as the first argument to the function.

There are two ways to solve your problem:

  1. Use a lambda expression:

    make_timer([](){ DataHandler::dh().send(); }, 20);
    
  2. Use std::bind:

    make_timer(std::bind(&DataHandler::send, DataHandler::dh()), 20);
    

Upvotes: 1

Related Questions