MATH000
MATH000

Reputation: 1103

How I can make the following work for functions members of a class?

The following is a timer.

template <typename Duration, typename Function>
void timer(Duration const & d, Function const & f)
{
    std::thread([d,f](){
        std::this_thread::sleep_for(d);
        f();//error here
    }).detach();
}

Sample myclass definition is

class myclass {
public:
    void my_functions() const {
        std::cout << "my_functions called";
    }
};

And I call it like this:

timer(std::chrono::milliseconds(10), &myclass::my_functions());

When I try to call it on a member function I get error C2064: term does not evaluate to a function taking 0 arguments

Upvotes: 0

Views: 62

Answers (4)

NathanOliver
NathanOliver

Reputation: 180630

The issue here is a non static member function is not the same as a regular or static function. It has a hidden parameter that it takes and that is pointer to the object the function is being called on.

You have a couple ways to fix this. First you can make it static and then it treats it just like a normal function whose name is scopeed to the class. If you cannot do that then you can use std::bind to create function like object that you can call the function operator on. It would be used like

timer(std::chrono::milliseconds(10), std::bind(&class_name::my_functions(), &class_instance));

Lastly you could use a lambda to wrap the call just like bind does. For that the syntax would be

timer(std::chrono::milliseconds(10), [&class_instance](){
    return class_instance.my_functions(); 
});

Upvotes: 1

buld0zzr
buld0zzr

Reputation: 962

To pass a non-static member function to another function you need to utilize std::function and std::bind from functional header, as well as instantiate the object

myclass mc;
timer(std::chrono::milliseconds(1), std::bind(&myclass::my_functions, mc));

However, your code might not work as expected, because to see the message you must wait for the thread to make a call. Here's a simple example of a working one

#include <thread>
#include <iostream>
#include <functional>
#include <chrono>

template <typename Duration, typename Function>
void timer(Duration const & d, Function const & f)
{
    std::thread([d, f](){
        std::this_thread::sleep_for(d);
        f();//error here
    }).detach();
}

class myclass{
public:
    void my_functions() const {
        std::cout << "aaa";
    }
};

int main(){
    myclass mc;
    timer(std::chrono::milliseconds(1), std::bind(&myclass::my_functions, mc));
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}

The proper way would be of course to wait for thread completion.

Also, if the sole purpose of your member function is to output a message, you can make it static and do without binding.

Upvotes: 2

Manthan Tilva
Manthan Tilva

Reputation: 3277

If you are okay to charge argument list of your timer() function then this will also works.

#include <iostream>
#include <chrono>
#include <thread>

template <typename Duration, typename Function, typename Class>
void timer(Duration const & d, Function const & f,Class const& o)
{
    std::thread([d,f,o](){
        std::this_thread::sleep_for(d);
        f(o);//error here
    }).detach();
}
class Foo{
public:
    Foo() {}
    void func() const {
        std::cout<<__func__<<":"<<__LINE__<<std::endl;};
    }

int main(){
    std::function<void(const Foo&)> foo_func = &Foo::func;
    const Foo foo;
    timer(std::chrono::seconds(2),foo_func,foo);
    std::this_thread::sleep_for(std::chrono::seconds(5));
    return 0;
}

Upvotes: 1

Aganju
Aganju

Reputation: 6395

You cannot call non-static methods/functions without an object instance (even if the object is not really needed inside the method/function).

To achieve a method call without the need for an object, declare that method static (can still be inside the class, but add static before its name).

Upvotes: 1

Related Questions