Reputation: 159
I was able to pass an object's non static method Dummy to another object's function. The problem comes when I try to store the reference of that method into the object of the function, I don't know how to do it.
#include <iostream>
#include <functional>
class Dummy{
public:
void runDummyArgs(int z){std::cout<<"TEST: "<<z<<std::endl;};
};
class Test{
public:
template<typename X , typename T>
void runTest(X* obj, T(X::* func), int z) { (obj->*func)(z); };
/* It works, but I would like to store (obj->*func) in this class as a reference to reuse it when it is needed. */
};
int main()
{
Dummy *a = new Dummy();
Test *b = new Test();
b->runTest(a, &Dummy::runDummyArgs, 99);
return 0;
}
Upvotes: 1
Views: 499
Reputation: 33931
I would write something that looks like:
#include <iostream>
#include <functional>
class Dummy{
public:
void runDummyArgs(int z){std::cout<<"TEST: "<<z<<std::endl;};
};
class Test{
std::function<void(int)> mFunc; // added member to hold function
public:
// added constructor to accept function
Test(std::function<void(int)> func): mFunc(func)
{
}
// no longer needs any templating. It's all handled by std::function
// most of the parameters bound by std::function
void runTest(int z)
{
mFunc(z);
};
};
int main()
{
Dummy a; // no need for dynamic allocation. Only use new when forced
// and that's almost never thanks to containers and smart pointers
// This line gets a bit weird. I'll explain it below
Test b([&a](int z){a.runDummyArgs(z);});
b.runTest(99); // just needs the end argument of the function
return 0;
}
OK. That's not so bad. Except for
Test b([&a](int z){a.runDummyArgs(z);});
Test
requires a std::function
that takes an int
and returns nothing. [&a](int z){a.runDummyArgs(z);}
is a lambda expression (More documentation that gets into the niggly bits and details) that defines a callable object that takes an int
and returns nothing. The resulting instance will be called b
. Breaking the lambda down further:
[&a]
Captures variable a
by reference. This allows modifying a
inside the lambda. Sometimes you want the lambda to carry around its own copy of a
, for example if a
is a temporary variable that won't be around when the function is called later. To stave off the common future questions about dangling references and const Dummy
compiler errors, I'll add a simple example of capture by mutable
value to the end of this answer.
(int z)
lambda's parameters
{a.runDummyArgs(z);}
function body that invokes runDummyArgs
on a
.
More complicated capture by mutable value example:
#include <iostream>
#include <functional>
class Dummy{
int val = 0; // provide some visible state for instances
public:
void runDummyArgs(int z)
{
std::cout<<"TEST: "<<z + val << std::endl;
// ^ added to show changing state
val++; // change state
}
};
class Test{
std::function<void(int)> mFunc;
public:
Test(std::function<void(int)> func): mFunc(func)
{
}
void runTest(int z)
{
mFunc(z);
};
};
std::function<void(int)> builder()
{
Dummy a;
return [a](int z)mutable{a.runDummyArgs(z);};
// ^ the copy of a can be modified.
} // a goes out of scope here, but its copy in the lambda lives on
int main()
{
Test b(builder());
b.runTest(99); // print 99
b.runTest(99); // print 100
Test c(builder());
c.runTest(99); // print 99 because we have a copy of a different dummy instance
c.runTest(99); // print 100
return 0;
}
Upvotes: 1