Username
Username

Reputation: 171

How to use functions with different parameters as a function parameter

The title may be a bit confusing, so I will explain it more clearly.

I have a class like:

class foo
{
public:

   foo(%Some function% *) { %Some function pointer% = %Some function%; }

   %Some output% callFunction(%Some input%);

private:

   %Some function pointer% bar;
}

Preferably, I would like to be able to store the given function in %Some function pointer% to be used throughout the class, but this isn't necessary.

So my main question is: How could I create a real callFunction that can take in any function as an input, along with that functions parameters?

Any help is appreciated!

Upvotes: 1

Views: 150

Answers (1)

Guillaume Racicot
Guillaume Racicot

Reputation: 41750

You will need to know somewhere what will be the return and parameter types. Either fixed in the class or in template parameters.

Here's an example of fixed in the class:

struct foo {
    foo(std::function<int(std::string, double)> func) : bar{std::move(func)} {}

    int callFunction(std::string s, double d) {
        bar(std::move(s), d);
    }

private:
    std::function<int(std::string, double)> bar;
};

This method does not only allow function pointers, but any function-like object too, like a lambda.

If you don't want the types to be fixed, then you can use templates to specify the type of the function object you'd like to wrap:

template<typename F>
struct foo {
    foo(F func) : bar{std::move(func)} {}

    template<typename... Args>
    auto callFunction(Args&&... args) -> decltype(bar(std::declval<Args>()...)) {
        return bar(std::forward<Args>(args)...);
    }

private:
    F bar;
};

template<typename F>
auto make_foo(F f) {
    return foo<F>{std::move(f)};
}

This method allows any function or function-like object, and is also faster than the other solution because it does not drag the std::function overhead. The downside here is you must use make_foo prior C++17.

You can then use the solution above like this:

auto f1 = make_foo([](int i){ return i * 1.5; });
auto f2 = make_foo([]{});

double result = f1.callFunction(12);
f2.callFunction();

If you flip on the switch for C++17, then you can write that:

foo f1 = [](int i){ return i * 1.5; };
foo f2 = []{};

double result = f1.callFunction(12);
f2.callFunction();

Note that f1and f2 are still instances of different types. The template parameter is hidden through deduction.

Upvotes: 1

Related Questions