C++ method resolution by name - c++

I am wondering if there is a way in C++ to write a function that will resolve object methods based on the method name alone (specific examples below). Run time or compile time resolution (such as templates) would both be acceptable. I have read a little bit about template metaprogramming, but I was hoping I might get some info as to whether that is even the appropriate direction for my problem before delving to deep into that.
Essentially, I am trying to write a function that will call non-static methods of a passed in object, such as this psuedocode:
exampleFunction(Object myObject, ObjectMethod myObjectMethod) {
// do some stuff here
myObject.myObjectMethod(arguments);
// do some more stuff here
}
In this case, I cannot hard-code a method into exampleFunction and simply have every object that I call it with have that method name. I must have the flexibility to call exampleFunction with a variety of methods, and have each of those methods properly resolve. Further, I must be able to resolve methods, and those methods must be non-static. In my case, I must be able to modify internal, private object members on the method call. Without going into the details, these constraints are an artifact of the system I am working on that I cannot change.
As I previously stated, both compile time and run time solutions are acceptable. So something like this with templates would work perfectly well in my case as well:
template <ObjectMethodName methodName>
exampleFunction(Object myObject) {
// do some stuff here
myObject.methodName(arguments);
// do some more stuff here
}
Any thoughts on whether this is possible, as well as information on possible implementation would be appreciated.

You can make exampleFunction a function template that has the first parameter of type of the object, the second parameter can be a reference to a pointer to a member function and the third parameter is a function parameter pack that denotes the arguments to be passed when calling the member function.
#include <iostream>
class Actions {
public:
Actions(){}
void doSmthg(){
std::cout<<"do something called"<<std::endl;
}
void multipleArgs(int, int)
{
std::cout<<"multiple int args called"<<std::endl;
}
};
class Entity
{
public:
void func(double)
{
std::cout<<"func called"<<std::endl;
}
};
template<typename T, typename Callable, typename... Args>
void exampleFunction(T obj, const Callable& callable, const Args&... args){
std::cout<<"exampleFunction called"<<std::endl;
//call the function on the passed object
(obj.*callable)(args...);
}
int main()
{
Actions action;
exampleFunction(action, &Actions::doSmthg); //calls doSmthg member function with 0 arguments
exampleFunction(action, &Actions::multipleArgs, 5,7);//calls multipleArgs member function with 2 int arguments
Entity e;
exampleFunction(e, &Entity::func,4.4); //calls func member function
}
Demo
The output of the above program is:
exampleFunction called
do something called
exampleFunction called
multiple int args called
exampleFunction called
func called

It's possible to pass a pointer-to-member-function as a template parameter.
Here is one example approach.
#include <iostream>
struct Foo {
void print() {
std::cout << "Foo\n";
}
void printVal(int val) {
std::cout << "val = " << val << "\n";
}
};
template <auto F, typename T, typename... Args>
void exampleFunc(T& obj, Args&&... args) {
(obj.*F)(args...);
}
int main()
{
Foo foo;
exampleFunc<&Foo::print>(foo);
exampleFunc<&Foo::printVal>(foo, 5);
}
Using auto template parameters requires c++17.

Related

How can I create a function that takes another function as a parameter with an unknown number of arguments?

I'm creating an onClick function. The premise is that when a button is clicked, It will call a function like so:
// This connects the callback to the button class method named "something"
something.onClick(&callback, "a string", 123);
// This is called when the button is clicked
callback("a string", 123);
I'm already using a function pointer to call the function callback, however I don't know how to accept a variable number of arguments. The API I want is exactly like I specified above: the first parameter is the function, and each subsequent parameter is an argument to be passed. So far I've thought about using boost::bind, but am unable to figure out how that will fit in with what I'm attempting.
You can just capture the supplied arguments in a lambda. This can't be stored in a function pointer, so use std::function
class Something
{
public:
template <typename Func, typename ... Args
void onClick(Func&& func, Args&& ... args)
{
m_onClick = [=]{ func(args...); };
}
private:
std::function<void()> m_onClick;
// call m_onClick somewhere
};
int main () {
Something something;
something.onClick(&callback, "a string", 123);
}
How would you call the function if you dont know how many parameters it has? There are solutions for that, but why not keep it simple...
Lets say you want to use either one of the two as callback:
void foo(std::string x) {}
void bar(int x) {}
Then you can wrap them together with the parameters in a lambda and store it in a std::function like that:
#include <string>
#include <functional>
void foo(std::string x) {}
void bar(int x) {}
struct caller {
std::function<void()> callback;
void call() { callback(); }
};
int main(){
caller c{ [](){ foo("test"); }};
c.call();
caller d{ [](){ bar(1); }};
d.call();
}
If the parameters to be passed are supposed to be more dynamic you need something more of course.

Passing void method with parameters to another method with std::function and std::bind C++

class A
{
public:
A() {}
void print(std::function<void(int)> func);
virtual ~A() {}
};
void A::print(std::function<void(int)> func)
{
func();
}
void printInt(int a)
{
std::cout << a << std::endl;
}
int main()
{
A a;
a.print(std::bind(&printInt, 3));
return 0;
}
Let's say I have this sample of code. How to pass void method printInt(int a) to A::print(std::function func) and call there function that has been passed? I get "candidate expects 1 argument, 0 provided" and I don't know how to deal with that.
Edit:
I should have mentioned it but my goal is to pass that integer but actually I have no idea how. When I try something like this:
void A::print(std::function<void(int a)> func)
{
func(a);
}
I get "error: ‘a’ was not declared in this scope".
If you don't intend to pass any arguments to func, it should be std::function<void(void)>. A signature of void(int) means you intent to feed it an integer, something it will expect. And your code clearly doesn't provide the required argument.
If you do intent to pass an argument to func, it needs to be a parameter of A::print, like so:
void A::print(std::function<void(int)> func, int a) {
func(a);
}
Your attempt specified the functions parameter is named a which is moot. Since there is no a in A::print to refer to. The above also means you can dispense with bind:
a.print(&printInt, 3);
Your bind() creates a function that takes no arguments but A::print expects a function that takes 1. It then tries calling that function as if it takes no arguments.
The answer is to change A::print to take a std::function that takes no arguments.

Access violation on std::function assigned to a lambda

I was trying to play around with std::function and std::bind and I stepped in a problem. I would like to build a general structure that allows me to bind a std::function to a member function without knowing a priori the arguments of the member function. I wrote this thing
template<typename Class, typename Return, typename ...Args>
struct Caller
{
private:
std::function<Return(Args ...)> callerFunction;
Caller(const Caller&) = delete;
Caller(Caller&&) = delete;
Caller& operator=(const Caller&) = delete;
public:
~Caller() = default;
Caller() = default;
Caller(Class& instance, Return(Class::*function)(Args...))
{
callerFunction = [&](Args... args) { return (instance.*function)(args...); };
}
Return operator() (Args ... args)
{
return callerFunction(args...);
}
};
FYI I know that the arguments to the function are passed by value (I encountered some problem using universal references with variadic template, I will work on that later).
The problem here is that when I fire the function with operator() I get an Access Violation Error. I tried to narrow down the problem and created a structure without the variadic arguments (allowing the member function to have just an int as argument) and I saw that assigning the lambda to the std::function was given me the same error, but if I used std::bind with a placeholder everything was just fine.
The test ground is this
class A
{
public:
bool foo(int a)
{
std::cout << a << std::endl;
return true;
}
};
int main()
{
A a;
a.foo(9);
Caller<A, bool, int> caller(a, &A::foo);
caller(10);
std::cin.ignore();
}
Using the lambda, do I need to save the instance of the class in order to call properly the member function?
As state in comment, you have dangling pointer of function, you could use instead:
Caller(Class& instance, Return(Class::*function)(Args...))
{
callerFunction = [&instance, function](Args... args) {
return (instance.*function)(std::forward<Args>(args)...);
};
}
Note: instance should also outlives Caller.
Don't use [&] when the object or copies of it outlives the current scope.
You are capturing references to local variables and storing them beyond the current scope.

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
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.
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).
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;
}
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();
});

Parameter/storage type for a C++11 lambda

In C++11, how do you declare a function that takes a lambda expression as an argument? I can find plenty of resources online for declaring lambdas or taking them as template parameters, but what I'd really like to do is be able to make use of lambdas as easy-to-declare callback handlers, similar to what's made possible by closures in JavaScript and code blocks in Objective-C.
Essentially, the classic C++ construct I want to replace with a lambda is something like:
class MyCallback {
public:
virtual ~MyCallback() {}
virtual void operator(int arg) = 0;
};
void registerCallback(const std::shared_ptr<MyCallback> &);
void foo(void) {
int a, b, c;
class LocalCallback: public MyCallback {
int a, b, c;
public:
LocalCallback(int a, int b, int c): a(a), b(b), c(c) {}
void operator(int arg) { std::cout << (a+b+c)*arg << std::endl; }
};
registerCallback(std::shared_ptr<MyCallback>(new LocalCallback(a,b,c)));
}
which would be simplified into:
void registerCallback(/* WHAT GOES HERE? */);
void foo(void) {
int a, b, c;
registerCallback([=](int arg){std::cout << (a+b+c)*arg << std::endl; })
}
So, what goes where I have written /* WHAT GOES HERE? */?
EDIT: This is for the purpose of storing a callback to be called back later, rather than for it being immediately consumed and called.
Usually const std::function<void(int)> & or std::function<void(int)>.
I'm not sure what the verdict is on whether std::function should be passed by const reference or by value. Probably by value is fine, especially since you're going to copy it anyway to store.
In case it isn't clear in the middle of all that syntax, void(int) is a function type, and std::function<T> means approximately, "a functor with the same signature as functions of type T".
Lambdas themselves have anonymous types. There is no way to name the type of your lambda expression, and the types of different lambda expressions with the same signature are different:
auto foo = [=](int arg){std::cout << (a+b+c)*arg << std::endl; };
auto bar = [=](int arg){std::cout << (a+b+c)*arg << std::endl; };
// foo and bar have different types, accessible as decltype(foo), decltype(bar)
Hence the need for std::function, which basically is a type-erasing wrapper to gather together different functors with the same signature into a common type. It's the bridge between static polymorphism with templates, and the dynamic polymorphism you need if you want to register a callback, store it for later, and then call it without having "remembered" the original type.
void registerCallback(const std::function<void(int)>& callback);
Consider using a function template. There are a variety of good reasons to, such as better behaviour when overloading (overloading on std::function is painful):
template<typename Functor>
void registerCallback(Functor&& functor);
(You can also accept the parameter as Functor functor, that's not too important.)
If the code needs to e.g. store the functor later on, then that will likely be held inside an std::function. Where you want to avoid std::function is in function parameters.