c++templatesvariadic-templatesvariadic-functionsvariadic

Passing variadic arguments to a method once object is constructed


I'm trying to build a template class that once constructed with its variadic arguments has its member functions use these arguments without the user having to manually insert them back. This code (modified from this post) takes the arguments in the constructor and doesn't require them in the operator overload:

struct FunctionBase
{
    virtual ~FunctionBase() {}
};

template<numeric T, numeric... Args>
struct Function : public FunctionBase
{
public:
    Function(Args... params)
        : argsTuple(params...)
    {}

    const virtual T operator()(T x)
    {
        return callExpr(x, std::index_sequence_for<Args...>{});
    }

protected:
    template<std::size_t... I>
    const T callExpr(T x, std::index_sequence<I...>)
    {
        return expression(x, std::get<I>(argsTuple)...);
    }

    const virtual T expression(T x, Args... params)
    {
        // Do arithmetic operations
        return 0;
    }

    std::tuple<Args...> argsTuple;
};

Here I'm storing the arguments of the constructor in a tuple that is then used to pass them to expression(T x, Args... params) in callExpr(T x, std::index_sequence<I...>).

Is there a way to avoid the intermediate function calls, such as that of callExpr and std::get<I>(argsTuple)...? Currently this method is incredibly slow.


Solution

  • There is std::apply which avoids you do the indirection yourself.

    const virtual T operator()(T x)
    {
        return std::apply([&](const auto&... args){ return expression(x, args...); },
                          argsTuple);
    }
    

    std::function is another alternative:

    template<numeric T, numeric... Args>
    struct Function : public FunctionBase
    {
    public:
        Function(Args... params) : func([=](T x) { return expression(x, params...); })
        {}
    
        const virtual T operator()(T x) { return func(x); }
    
    protected:
        const virtual T expression(T x, Args... params)
        {
            // Do arithmetic operations
            return 0;
        }
    
        std::function<T(T)> func;
    };