Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 variadic templates calling a function inside a class

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.

like image 343
Medical physicist Avatar asked Jan 30 '26 22:01

Medical physicist


1 Answers

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;
}

Demo 1

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;
}

Demo 2

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;
}

Bonus Demo

like image 54
Moia Avatar answered Feb 02 '26 14:02

Moia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!