【问题标题】:Save and pass to function list of template arguments in C++保存并传递给 C++ 中模板参数的函数列表
【发布时间】:2020-10-28 12:22:05
【问题描述】:

我想保存模板参数列表并将其传递给函数。
就像std::thread 将参数传递给线程。参数类型是模板化的,参数计数不是静态的。

例如,它是如何工作的:

class CallbackList {
public:
    Callback(/* Type of list of template args */ args) {
        this->saved_args = args;
    }


    void Call() {
        this->callback(saved_args);
    }
private:
    /* Type of list of template args */ saved_args;

    CallbackType callback;
}   

或者我该如何实现:

template<typename ...Args>
class CallbackList {
public:
    using CallbackPrototype = /* some prototype */;

    void RegisterCallback(CallbackPrototype callback, Args... args) {
        CallbackInfo callback_info;
        callback_info.callback = callback;
        callback_info.args = { args... };
        this->callbacks.push_back(callback_info);
    }

    void Call() {
        for (CallbackInfo& callback_info : this->callbacks)
            callback_info.callback(callback_info.args);
    }

private:
    struct CallbackInfo {
        CallbackPrototype callback;
        /* what type should be here? tuple? args count are not static */ args;
    };

    std::vector<CallbackInfo> callbacks;
}   

有可能吗?
如何实现?

【问题讨论】:

  • 您可以将Callback 设为类模板还是将不同的回调对象存储在单个容器中?
  • 您正在寻找可变参数模板。这是一个广泛的话题,我建议你看一些例子,例如:en.cppreference.com/w/cpp/language/parameter_pack
  • 实际的callback 是如何设置的?它从未在这里初始化。
  • @NathanOliver,我可以将类模板化为@AndyG,这是示例,callback 字段将被初始化我还添加了第二个示例,更接近我的实际任务

标签: c++ templates callback variadic-templates


【解决方案1】:

如果你不希望你的回调依赖于参数的类型,你必须使用某种类型擦除。例如,您可以使用来自&lt;functional&gt;std::function

#include <functional>
#include <iostream>


class Lazy_Callback
{
public:
  template <typename F, typename ...Args>
  Lazy_Callback(F && f, Args && ...args)
  : _fun([=]() { return f(args...); })
  { }
    
  void call() const
  {
    _fun();
  }
protected:
private:
  std::function<void()> _fun;
};

void print_int(int x)
{
  std::cout << "x = " << x << "\n";
}

int main()
{
  Lazy_Callback lc(print_int, 5);
  
  lc.call();
}

如果回调可以被模板化,那么您可以使用std::tuple 来存储您的参数:

#include <tuple>
#include <iostream>



template <typename F, typename ...Args>
class Lazy_Callback
{
public:
  template <typename ...Ts>
  Lazy_Callback(F f, Ts && ...ts)
  : _f(f), _args(ts...)
  { }
  
  void call() const
  {
    return std::apply(_f, _args);
  }
  
protected:
private:
  F _f;
  std::tuple<Args...> _args;
};



template <typename F, typename ...Ts>
Lazy_Callback<F, std::decay_t<Ts>...> make_callback(F && f, Ts && ...ts)
{
  return { std::forward<F>(f), std::forward<Ts>(ts)... };
}

void print_int(int x)
{
  std::cout << "x = " << x << "\n";
}

int main()
{
  auto lc = make_callback(print_int, 5);
  
  lc.call();
}

【讨论】:

    【解决方案2】:

    您是否正在寻找类似std::bind 的内容?下面是一个简单的例子,你可以扩展:

    #include <iostream>
    #include <functional>
    
    template <typename T1, typename T2>
    void printSum(const T1& a, const T2& b)
    {
        std::cout << a + b << std::endl;
    }
    
    int main()
    {
        const auto callback = std::bind(&printSum<int, int>, 1, 2);
    
        // ...
        
        callback();
    }
    

    【讨论】:

    • 我添加了第二个示例,更接近我的实际问题。它应该是动态的,存储在内存中。有可能吗?
    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    相关资源
    最近更新 更多