1

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!

3
  • Probably something like this: stackoverflow.com/questions/17805969/… Commented Dec 31, 2016 at 4:48
  • Just to clarify, you want foo::callFunction to take the arguments given to it %Some input% and you want it to call bar passing along those arguments and returning whatever bar returns? IOW, kind of like a passthrough/proxy function? Commented Dec 31, 2016 at 9:08
  • @greatwolf Yes, that is what I am trying to accomplish, but I'm not exactly sure how to do it. Commented Dec 31, 2016 at 19:43

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a great answer! Thanks for your help, and also the C++17 tip.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.