Search code examples
c++variadic-templates

How to store any kind of function in a variable in C++?


How would I go about storing any type of function with any number of arguments in a variable? Something like this:

int add(int i, int j) {
return i + j;
}

template<typename Function, typename... Args>
class Class {
private:
    std::function<Function(Args...)> function;
public:
    Class(Function _function, Args... _args) {
        Now what?
    }
};

int main() {
    Class test(add, 1, 2);
    test.function();
}

Solution

  • This is what bind is for!

    Your Class is effectively just std::bind. Let's imagine that you have further use for it, and make it wrap the std::bind logic. So we need to store a std::function that accepts no further arguments, and returns (in this case) int… but we'll make it generic (ReturnType).

    Then during initialisation you "bind" the arguments with which you constructed Class, and forward them into the std::function (the use of std::forward permitting move semantics for more complex argument types).

    #include <functional>
    #include <iostream>
    
    int add(int i, int j)
    {
        return i + j;
    }
    
    template <typename Function, typename... Args>
    class Class
    {
    private:
        using ReturnType = std::invoke_result_t<Function, Args...>;
        std::function<ReturnType()> function;
    
    public:
        Class(Function _function, Args... _args) 
            : function(std::bind(_function, std::forward<Args>(_args)...))
        {}
    
        auto Call()
        {
            return function();
        }
    };
    
    int main() {
        Class test(add, 1, 2);
        std::cout << test.Call() << '\n';
    }
    
    // Output: 3
    

    (live demo)

    Or, if you don't need Class to do anything more, it's just:

    #include <functional>
    #include <iostream>
    
    int add(int i, int j)
    {
        return i + j;
    }
    
    int main()
    {
        auto func = std::bind(add, 1, 2);
        std::cout << func() << '\n';
    }
    
    // Output: 3
    

    (live demo)


    Bootnote

    Your std::function<Function(Args...)> type is wrong because Function is the type of the whole function, but you've used it like a return type.