C++11:我可以从多个 args 到 tuple,但是我可以从 tuple 到多个 args 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10766112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:25:41  来源:igfitidea点击:

C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args?

c++templatesc++11variadic-templates

提问by Thomas

Possible Duplicate:
How do I expand a tuple into variadic template function's arguments?
“unpacking” a tuple to call a matching function pointer

可能的重复:
如何将元组扩展为可变参数模板函数的参数?
“解包”一个元组以调用匹配的函数指针

In C++11 templates, is there a way to use a tuple as the individual args of a (possibly template) function?

在 C++11 模板中,有没有办法使用元组作为(可能是模板)函数的单个参数?

Example:
Let's say I have this function:

示例:
假设我有这个功能:

void foo(int a, int b)  
{  
}

And I have the tuple auto bar = std::make_tuple(1, 2).

我有元组auto bar = std::make_tuple(1, 2)

Can I use that to call foo(1, 2)in a templaty way?

我可以使用它以foo(1, 2)模板方式调用吗?

I don't mean simply foo(std::get<0>(bar), std::get<1>(bar))since I want to do this in a template that doesn't know the number of args.

我的意思不仅仅是foo(std::get<0>(bar), std::get<1>(bar))因为我想在不知道参数数量的模板中执行此操作。

More complete example:

更完整的例子:

template<typename Func, typename... Args>  
void caller(Func func, Args... args)  
{  
    auto argtuple = std::make_tuple(args...);  
    do_stuff_with_tuple(argtuple);  
    func(insert_magic_here(argtuple));  // <-- this is the hard part  
}

I should note that I'd prefer to not create one template that works for one arg, another that works for two, etc…

我应该注意,我不希望创建一个适用于一个参数的模板,另一个适用于两个参数,等等......

回答by Kerrek SB

Try something like this:

尝试这样的事情:

// implementation details, users never invoke these directly
namespace detail
{
    template <typename F, typename Tuple, bool Done, int Total, int... N>
    struct call_impl
    {
        static void call(F f, Tuple && t)
        {
            call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
        }
    };

    template <typename F, typename Tuple, int Total, int... N>
    struct call_impl<F, Tuple, true, Total, N...>
    {
        static void call(F f, Tuple && t)
        {
            f(std::get<N>(std::forward<Tuple>(t))...);
        }
    };
}

// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
    typedef typename std::decay<Tuple>::type ttype;
    detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}

Example:

例子:

#include <cstdio>
int main()
{
    auto t = std::make_tuple("%d, %d, %d\n", 1,2,3);
    call(std::printf, t);
}

With some extra magic and using std::result_of, you can probably also make the entire thing return the correct return value.

通过一些额外的魔法和使用std::result_of,您可能还可以使整个事物返回正确的返回值。

回答by Jonathan Wakely

Create an "index tuple" (a tuple of compile-time integers) then forward to another function that deduces the indices as a parameter pack and uses them in a pack expansion to call std::geton the tuple:

创建一个“索引元组”(编译时整数元组),然后转发到另一个函数,该函数将索引推导出为参数包,并在包扩展中使用它们来调用std::get元组:

#include <redi/index_tuple.h>

template<typename Func, typename Tuple, unsigned... I>  
  void caller_impl(Func func, Tuple&& t, redi::index_tuple<I...>)  
  {  
    func(std::get<I>(t)...);
  }

template<typename Func, typename... Args>  
  void caller(Func func, Args... args)  
  {  
    auto argtuple = std::make_tuple(args...);  
    do_stuff_with_tuple(argtuple);
    typedef redi::to_index_tuple<Args...> indices;
    caller_impl(func, argtuple, indices());
  }

My implementation of index_tupleis at https://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.hbut it relies on template aliases so if your compiler doesn't support that you'd need to modify it to use C++03-style "template typedefs" and replace the last two lines of callerwith

我的实现index_tuple是在https://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.h但它依赖于模板别名所以如果你的编译器不支持你需要修改它用C ++ 03式“模板类型定义”并替换的最后两行caller

    typedef typename redi::make_index_tuple<sizeof...(Args)>::type indices;
    caller_impl(func, argtuple, indices());

A similar utility was standardised as std::index_sequencein C++14 (see index_seq.hfor a standalone C++11 implementation).

std::index_sequence在 C++14 中标准化了一个类似的实用程序(有关独立的 C++11 实现,请参阅index_seq.h)。