Generic function that any class member can take in a C ++ parameter
I have some tests for class methods. I am having difficulty using std :: function for this. Here's some sample code to simplify the problem:
#include <iostream>
#include <functional>
template<typename T>
struct Foo
{
Foo(T sum) : sum_(sum) {};
Foo<T> method_one(const Foo<T>& foo) const { Foo<T> res(sum_ + foo.sum_); return res; }
Foo<T> method_two(const Foo<T>& foo) const { Foo<T> res(sum_ + foo.sum_ + 10); return res; }
Foo<T> method_three(const Foo<T>& foo, T val) const { Foo<T> res(sum_ + foo.sum_ + val); return res;}
friend std::ostream &operator << (std::ostream & output, const Foo &foo) { output << foo.sum_; return output;}
T sum_;
};
template<typename T>
void do_the_work(const Foo<T>& a, const Foo<T>& b, const std::function<Foo<T>(const Foo<T>&)> &func)
{
// I do stuff before [...]
Foo<T> c = a.func(b);
std::cout << c << std::endl;
// I do stuff after [...]
}
int main()
{
Foo<float> a(1.0);
Foo<float> b(2.0);
// I would like to replace this
Foo<float> c = a.method_two(b);
std::cout << c; // 1 + 2 + 10
// with something like that
do_the_work(a, b, a.method_one);
do_the_work(a, b, a.method_two);
// and if possible make it more generic...
do_the_work(a, b, a.method_three, 12);
}
I tried using bind in main () with no success:
std::function<Foo<float>(const Foo<float>&)> f = std::bind(&Foo<float>::method_one, &a);
Any other elegant solution would be nice. As you can see, this prevents code redundancy and makes it "do things before or after" multiple times.
source to share
I would skip the use std::function
in the signature do_the_work
and allow it all internally. This makes it easier to include additional arguments:
template<typename T, typename Func, typename... Args>
void do_the_work(const Foo<T>& a,
const Foo<T>& b,
Func func,
Args&&... args)
{
auto f = std::bind(func, a, b, std::forward<Args>(args)...);
// I do stuff before [...]
Foo<T> c = f();
std::cout << c << std::endl;
// I do stuff after [...]
}
And later
do_the_work(a, b, &decltype(a)::method_one);
do_the_work(a, b, &decltype(a)::method_two);
// and if possible make it more generic...
do_the_work(a, b, &decltype(a)::method_three, 12);
source to share
You are missing an implicit parameter this
for your member function, you must specify it in the signature std::function
:
template<typename T>
void do_the_work(const Foo<T>& a, const Foo<T>& b, std::function<Foo<T>(const Foo<T>&, const Foo<T>&)> func)
{
Foo<T> c = func(a, b);
...
}
Notice how std::function
(it is not a.foo(b)
) is called
And to call it:
do_the_work<float>(a, b, &Foo<float>::method_one);
do_the_work<float>(a, b, &Foo<float>::method_two);
If you want / can bind an object that your functions will be called on:
template<typename T>
void do_the_work_binded(const Foo<T>& b, std::function<Foo<T>(const Foo<T>&)> func)
{
// I do stuff before [...]
Foo<T> c = func(b);
std::cout << c << std::endl;
// I do stuff after [...]
}
...
std::function<Foo<float>(const Foo<float>&)> fb = std::bind(&Foo<float>::method_one, a, std::placeholders::_1);
do_the_work_binded(b, fb);
source to share