Vince
Vince

Reputation: 4439

Encapsulating arguments of variadic function in a class instance

Here some code with holes:

template<typename... Args>
class A 
{

  typedef function_type = void(*)(Args...);

  public:
  void set_args(Args&& ... args)
  {
      // something magic manages to encapsulate
      // args in instance of A
  }
  void apply_args(function_type function)
  {
      // something magic manages to "retrieve"
      // the encapsulated args
      function(std::forward<Args>(args)...);
  }

};

Would that be somehow possible ?

Upvotes: 3

Views: 106

Answers (2)

NutCracker
NutCracker

Reputation: 12273

You can store your template arguments in class data member of std::tuple type and the use std::apply in order to apply stored arguments to provided function.

So, let's say you have an Action class like this:

template <typename... Args>
class Action {
    std::tuple<Args...> args_;

public:
    Action() = default;
    Action(Args&&... args)
        : args_(std::forward<Args>(args)...)
    {}

    void args(Args&&... args) {
        args_ = std::make_tuple<Args...>(std::forward<Args>(args)...);
    }

    template <typename F>
    void apply(F&& fun) {
        std::apply(std::forward<F&&>(fun), args_);
    }
};

where you set arguments through constructor Action action(1, 2, 3); or through separate function action.set(3, 2, 1);.

Then your main function can look like this:

int main() {
    Action action(1, 2);

    action.apply([](int a, int b) {
        std::cout << "a + b = " << (a + b) << std::endl;
    });

    return 0;
}

Check live example

Upvotes: 3

const_ref
const_ref

Reputation: 4096

You can make use of std::tuple and std::apply

#include <iostream>
#include <tuple>
#include <functional>
#include <string>

template <typename... Ts>
class A
{
    private:
        std::function<void (Ts...)> f;
        std::tuple<Ts...> args;    
    public:
        template <typename F>
        A(F&& func, Ts&&... args)
            : f(std::forward<F>(func)),
              args(std::make_tuple(std::forward<Ts>(args)...))
        {}

        void Invoke()
        {
            std::apply(f, args);
        }
};

template <typename F, typename... Args>
A<Args...> Create(F&& f, Args&&... args)
{
    return A<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}

int main()
{
    auto helloWorld = Create([] (std::string a, std::string b) { std::cout << a << ", " << b; }, std::string("Hello"), std::string("World!"));

    helloWorld.Invoke();
}

Upvotes: 1

Related Questions