program tip

가변 템플릿 인수를 저장하는 방법은 무엇입니까?

radiobox 2020. 10. 15. 07:40
반응형

가변 템플릿 인수를 저장하는 방법은 무엇입니까?


나중에 사용하기 위해 어떻게 든 매개 변수 팩을 저장할 수 있습니까?

template <typename... T>
class Action {
private:        
    std::function<void(T...)> f;
    T... args;  // <--- something like this
public:
    Action(std::function<void(T...)> f, T... args) : f(f), args(args) {}
    void act(){
        f(args);  // <--- such that this will be possible
    }
}

그런 다음 나중에 :

void main(){
    Action<int,int> add([](int x, int y){std::cout << (x+y);}, 3, 4);

    //...

    add.act();
}

여기서 원하는 작업을 수행하려면 템플릿 인수를 튜플에 저장해야합니다.

std::tuple<Ts...> args;

또한 생성자를 약간 변경해야합니다. 특히로 초기화 args하고 std::make_tuple매개 변수 목록에서 범용 참조를 허용합니다.

template <typename F, typename... Args>
Action(F&& func, Args&&... args)
    : f(std::forward<F>(func)),
      args(std::forward<Args>(args)...)
{}

또한 다음과 같이 시퀀스 생성기를 설정해야합니다.

namespace helper
{
    template <int... Is>
    struct index {};

    template <int N, int... Is>
    struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};

    template <int... Is>
    struct gen_seq<0, Is...> : index<Is...> {};
}

그리고 이러한 생성기를 사용하는 방식으로 메서드를 구현할 수 있습니다.

template <typename... Args, int... Is>
void func(std::tuple<Args...>& tup, helper::index<Is...>)
{
    f(std::get<Is>(tup)...);
}

template <typename... Args>
void func(std::tuple<Args...>& tup)
{
    func(tup, helper::gen_seq<sizeof...(Args)>{});
}

void act()
{
   func(args);
}

그리고 그것! 이제 수업은 다음과 같이 보일 것입니다.

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

    template <typename... Args, int... Is>
    void func(std::tuple<Args...>& tup, helper::index<Is...>)
    {
        f(std::get<Is>(tup)...);
    }

    template <typename... Args>
    void func(std::tuple<Args...>& tup)
    {
        func(tup, helper::gen_seq<sizeof...(Args)>{});
    }

    void act()
    {
        func(args);
    }
};

다음은 Coliru에 대한 전체 프로그램입니다.


업데이트 : 다음은 템플릿 인수를 지정할 필요가없는 도우미 메서드입니다.

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

int main()
{
    auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3);

    add.act();
}

그리고 또 다른 데모가 있습니다.


You can use std::bind(f,args...) for this. It will generate a movable and possibly copyable object that stores a copy of the function object and of each of the arguments for later use:

#include <iostream>
#include <utility>
#include <functional>

template <typename... T>
class Action {
public:

  using bind_type = decltype(std::bind(std::declval<std::function<void(T...)>>(),std::declval<T>()...));

  template <typename... ConstrT>
  Action(std::function<void(T...)> f, ConstrT&&... args)
    : bind_(f,std::forward<ConstrT>(args)...)
  { }

  void act()
  { bind_(); }

private:
  bind_type bind_;
};

int main()
{
  Action<int,int> add([](int x, int y)
                      { std::cout << (x+y) << std::endl; },
                      3, 4);

  add.act();
  return 0;
}

Notice that std::bind is a function and you need to store, as data member, the result of calling it. The data type of that result is not easy to predict (the Standard does not even specify it precisely), so I use a combination of decltype and std::declval to compute that data type at compile time. See the definition of Action::bind_type above.

Also notice how I used universal references in the templated constructor. This ensures that you can pass arguments that do not match the class template parameters T... exactly (e.g. you can use rvalue references to some of the T and you will get them forwarded as-is to the bind call.)

Final note: If you want to store arguments as references (so that the function you pass can modify, rather than merely use, them), you need to use std::ref to wrap them in reference objects. Merely passing a T & will create a copy of the value, not a reference.

Operational code on Coliru


I think you have an XY problem. Why go to all the trouble to store the parameter pack when you could just use a lambda at the callsite? i.e.,

#include <functional>
#include <iostream>

typedef std::function<void()> Action;

void callback(int n, const char* s) {
    std::cout << s << ": " << n << '\n';
}

int main() {
    Action a{[]{callback(13, "foo");}};
    a();
}

참고URL : https://stackoverflow.com/questions/16868129/how-to-store-variadic-template-arguments

반응형