首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何存储可变模板参数?

如何存储可变模板参数?
EN

Stack Overflow用户
提问于 2013-06-01 09:20:08
回答 3查看 31.7K关注 0票数 92

是否可以以某种方式存储参数包以供以后使用?

代码语言:javascript
复制
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
    }
}

然后在后面:

代码语言:javascript
复制
void main(){
    Action<int,int> add([](int x, int y){std::cout << (x+y);}, 3, 4);

    //...

    add.act();
}
EN

回答 3

Stack Overflow用户

发布于 2013-06-01 10:10:03

您可以使用std::bind(f,args...)来实现这一点。它将生成一个可移动且可能可复制的对象,该对象存储函数对象和每个参数的副本以供以后使用:

代码语言:javascript
复制
#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;
}

注意,std::bind是一个函数,您需要将调用它的结果存储为数据成员。结果的数据类型不容易预测(标准甚至没有明确规定),所以我使用decltypestd::declval的组合在编译时计算该数据类型。请参阅上面对Action::bind_type的定义。

还要注意我是如何在模板化构造函数中使用通用引用的。这确保了您可以传递与类模板参数T...不完全匹配的参数(例如,您可以使用对一些T的右值引用,然后将它们按原样转发到bind调用)。

最后注意:如果您希望将参数存储为引用(以便您传递的函数可以修改它们,而不仅仅是使用它们),则需要使用std::ref将它们包装在引用对象中。仅仅传递一个T &就会创建一个值的副本,而不是一个引用。

Operational code on Coliru

票数 23
EN

Stack Overflow用户

发布于 2020-05-03 22:23:40

这个问题来自C++11 days。但对于那些现在在搜索结果中找到它的人,有一些更新:

通常情况下,std::tuple成员仍然是存储参数的直接方法。(如果您只想调用一个特定的函数,则类似于@jogojapan'sstd::bind解决方案也适用,但如果您想以其他方式访问参数,或将参数传递给多个函数等,则不起作用。)

在C++14和更高版本中,std::make_index_sequence or std::index_sequence_for可以取代0x499602D2's solution中的helper::gen_seq<N>工具

代码语言:javascript
复制
#include <utility>

template <typename... Ts>
class Action
{
    // ...
    template <typename... Args, std::size_t... Is>
    void func(std::tuple<Args...>& tup, std::index_sequence<Is...>)
    {
        f(std::get<Is>(tup)...);
    }

    template <typename... Args>
    void func(std::tuple<Args...>& tup)
    {
        func(tup, std::index_sequence_for<Args...>{});
    }
    // ...
};

在C++17和更高版本中,可以使用std::apply来负责对元组进行解包:

代码语言:javascript
复制
template <typename... Ts>
class Action
{
    // ...
    void act() {
        std::apply(f, args);
    }
};

下面的a full C++17 program展示了简化的实现。我还更新了make_action,以避免在tuple中使用引用类型,这对于右值参数来说总是不好的,对于左值参数来说则是相当危险的。

票数 7
EN

Stack Overflow用户

发布于 2013-06-01 12:28:30

我认为你有XY问题。当您可以在调用点使用lambda时,为什么要不厌其烦地存储参数包?即,

代码语言:javascript
复制
#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();
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16868129

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档