I'm learning variadic templates in C++11. How can I call test.finder
as a functional argument of test.var_finder
?
#include <functional>
#include <iostream>
class c_test {
public:
double finder(double a, double b = 0) {
return a + b;
};
template<typename... Args>
double var_finder(double c, Args... args, std::function<double (Args... args)> func) {
return c * func(args...);
};
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, 2, test.finder) << std::endl;
return 0;
}
My expected result is 0.1 * (2 + 0) = 0.2.
I guess you're a bit mixing the variadic template part with a bit of design-flaw
Let's start.
Preamble: the correct way to deal with variadic templates is to use rvalue-reference
and std::forward
to achieve perfect forwarding.
1) The easy way: you don't need class at all
you're actually not referring to any member so a class bring only complexity. It's better to refer to a free function for these cases
#include <functional>
#include <iostream>
double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
int main () {
std::cout << var_finder(0.1, finder, 2, 0) << std::endl;
return 0;
}
your function accept 2 parameters so you have to pass zero as second argument.
2) Using a class
The problem with your attempt is you want to call c_test.var_finder
with a function of c_test
itself. Now you have to figure what kind of design you want. You can make 2 assumption. First is "I want anyway a finder function inside my class", then you have to make it static
because it really does not use class member so you don't need an instance of c_test
, right? so using a free function or a static member function leaves the var_finder
implementation and you just have to call it this way
#include <functional>
#include <iostream>
class c_test {
public:
static double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
};
int main () {
c_test test;
std::cout << test.var_finder(0.1, &c_test::finder, 2, 0) << std::endl;
return 0;
}
second assumption you can do is "nope, I want any function member to be called with var_finder regardless where it comes from". I strongly discourage this approach because is carving a solution from a bad design, so I suggest to rethink your design to fall to solution 1 or 2.
3) Bonus: a nice design
You can add a non-variadic function and delegate the usage to the use of a lambda, which allow you to use a member function inside it without defining a variadic template to deal with that (and it is the common implementation for the std library functions).
#include <functional>
#include <iostream>
double finder(double a, double b = 0) {
return a + b;
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f, Args&&... args) {
return c * std::forward<Func>(f)(std::forward<Args>(args)...);
};
template<typename Func, typename... Args>
double var_finder(double c, Func&& f) {
return c * std::forward<Func>(f)();
};
class c_test
{
public:
double finder(double a, double b = 0) {
return a + b;
};
};
int main () {
double a = 2.0;
double b = 0.0;
// use as usual
std::cout << var_finder(0.1, finder, a, b) << std::endl;
// use with lambda
std::cout << var_finder(0.1, [a,b](){ return a+b; }) << std::endl;
// lambda with member argument, less gruesome than a variadic template calling a member function
c_test c;
std::cout << var_finder(0.1, [a,b, &c](){ return c.finder(a,b); }) << std::endl;
return 0;
}