【问题标题】:C++ How to store a parameter pack as a variableC ++如何将参数包存储为变量
【发布时间】:2013-03-21 01:19:27
【问题描述】:

目前我在尝试存储参数包时遇到问题,这是设计的示例代码:

template<typename Func, typename... Args>
void handleFunc(Func func, Args&&... args) {
    struct nest {
        Func nestFunc;
        Args... nestArgs; // I DONT KNOW WHAT TO DO HERE
        void setup(Func func, Args... args) {
            nestFunc = func;
            nestArgs = (args)...; // SO I CAN SET IT HERE
        }
        // Later I will forward this and run the function with its arguments
        unsigned process() {
            nestFunc(std::forward<Args>(nestArgs)...); // USE IT HERE
            return 0;
        }
    };
    nest* myNest;
    myNest->setup(func, (args)...);
}

这是问题所涉及的所有内容的示例,我需要将 稍后 调用的参数存储在我的嵌套结构中。另外,如果您有存储它的解决方案但设置它与我的不同,也请让我知道。谢谢。

【问题讨论】:

标签: c++


【解决方案1】:

从 2018 年开始编辑:在 C++17 中,这个问题的答案是不同的。您仍然必须将参数存储在::std::tuple 中,但是当调用函数::std::apply 时,它会处理解包此元组并为您调用该函数。如果您需要将索引技巧用于 ::std::apply 以外的其他用途,您应该研究一下 ::std::integer_sequence 和相关的辅助函数 ::std::make_index_sequence。

现在回到 2013 年的 C++11/14 答案。

您必须使用::std::tuple&lt;Args...&gt; 来存储它。但接下来的问题是如何在需要时打开它。为此,您需要使用一种称为“索引”的技术。

所以,这里有一个链接,指向我已经完成了您想要做的事情的地方。这里最相关的核心类是suspended_call。

https://bitbucket.org/omnifarious/sparkles/src/tip/sparkles/deferred.hpp?at=default

稍后,我将提取最相关的部分并将它们放在您的代码中。

This line:

auto saved_args = ::std::make_tuple(::std::move(args)...);

将参数保存到元组中。我在那里使用了::std::move,我认为这是正确的做法。但有可能我错了,我应该使用::std::forward。除了信号意图之外,我一直不清楚确切的区别。

使用保存的参数实际执行调用的代码可以在here 中找到。现在该代码完全针对我正在做的事情。实现索引技巧的位包括创建一组整数,这些整数映射到索引以用作::std::get&lt;I&gt; 模板的参数。一旦你有了这组整数,你就可以使用它来扩展对::std::get的调用,以获取所有元组元素作为单独的参数。

我将尝试以相对简单的方式编写代码:

#include <tuple>
#include <cstddef>
#include <string>
#include <utility>

template < ::std::size_t... Indices>
struct indices {};

template < ::std::size_t N, ::std::size_t... Is>
struct build_indices : build_indices<N-1, N-1, Is...>
{};

template < ::std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...>
{};

template <typename FuncT, typename ArgTuple, ::std::size_t... Indices>
auto call(const FuncT &f, ArgTuple &&args, const indices<Indices...> &)
   -> decltype(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...))
{
   return ::std::move(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...));
}

template <typename FuncT, typename ArgTuple>
auto call(const FuncT &f, ArgTuple &&args)
     -> decltype(call(f, args,
                      build_indices< ::std::tuple_size<ArgTuple>::value>{}))
{
    const build_indices< ::std::tuple_size<ArgTuple>::value> indices;

    return ::std::move(call(f, ::std::move(args), indices));
}

int myfunc(::std::string name, const unsigned int foo)
{
   return 0;
}

int foo(::std::tuple< ::std::string, const unsigned int> saved_args)
{
   return call(myfunc, ::std::move(saved_args));
}

很多代码都是从this page on the indices trick借来的。

另外,这是一个样本,您必须根据自己的具体情况稍作调整。基本上,只需在某处致电call(nestFunc, saved_args)。

【讨论】:

  • 如何将这个元组设置为 (args)...;
  • 您能否详细说明这些“指标”?
  • @David:是的,还有更多示例。你将拥有它们。实际上,我最近不得不编写执行此操作的代码。
  • @Omnifarious,有趣的是,我只是在想是否可以存储一个参数包以供以后扩展。例如,您的代码是否可以存储可调用对象以及参数列表以供以后调用?
  • @Omnifarious,Sweet,实际上填补了我一直想要的一些用途。老实说,很久以前我拥有的最好的就是带有绑定参数的std::function&lt;void()&gt;(它不需要返回值)。
【解决方案2】:

我知道这已经有一段时间了,但我有类似的需求并想出了这个解决方案,希望它对某人有所帮助:

#include <functional>

template<typename Func, typename... Args>
struct nest {
    std::function<void()> callBack;

    void setup(Func func1, Args... args) {
        callBack = [func1, args...]()
        {
            (func1)(args...);
        };
    }

    unsigned process() {
        callBack();
        return 0;
    }
};

template<typename Func, typename... Args>
void handleFunc(Func func, Args&&... args) {
    nest<Func, Args...> myNest;
    myNest.setup(func, args...);
}

【讨论】:

  • 针对极度残缺的 C++ 包语法的巧妙解决方法)
  • 将它们全部存储在 lambda 中而不是元组中非常聪明。
  • 虽然使用通用的 lambda 捕获表达式来转发所有参数(然后也在 lambda 内部的调用中转发它们)可能是一个更好的主意。
  • 这个实现完美转发了吗?
  • 这真的解决了我2天的寻找......谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 2021-08-21
  • 2013-04-01
相关资源
最近更新 更多