C++11:我可以从多个 args 转到 tuple,但我可以从 tuple 转到多个 args 吗? [复制]

Posted

技术标签:

【中文标题】C++11:我可以从多个 args 转到 tuple,但我可以从 tuple 转到多个 args 吗? [复制]【英文标题】:C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args? [duplicate] 【发布时间】:2012-06-01 17:26:19 【问题描述】:

可能重复:How do I expand a tuple into variadic template function's arguments?“unpacking” a tuple to call a matching function pointer

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

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

void foo(int a, int b)  
  

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

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

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

更完整的例子:

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  

我应该注意,我不想创建一个适用于一个 arg 的模板,另一个适用于两个 arg 的模板,等等……

【问题讨论】:

当然。你想要像template &lt;typename F, typename Tuple, int N...&gt; call(F f, Tuple const &amp; t) f(std::get&lt;N&gt;(t)...); 这样的东西。现在只需填写空白:-) 您的意思是跳过可变参数模板并改为创建多个caller() 模板吗? @Thomas:你必须制作一个小调度工具来构建整数包N...,并在N == std::tuple_size&lt;Tuple&gt;::value 时部分专门化,你想以我的方式调用原始函数建议。 (当然应该是int ...N。) 【参考方案1】:

试试这样的:

// 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));

例子:

#include <cstdio>
int main()

    auto t = std::make_tuple("%d, %d, %d\n", 1,2,3);
    call(std::printf, t);

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

【讨论】:

@JonathanWakely : call_impl 是一个实现细节——用户从不直接调用它,全局call 是用户交互的全部。这个例子不清楚吗? 啊,不,我只是没看清楚,我认为 call 是 OP 的 caller 的替代品,所以 call_impl 的笨拙使用发生在用户的代码中。跨度> 我的好先生,这令人困惑,值得一票。 这是我在 *** 上找到的最好的解压 std::tuple 的方法,而且它有一半的投票支持更糟糕的解决方案...... 只是一个建议,您可能想在其中抛出一个auto 进行调用,这样您也可以使用函数的返回值,顺便说一句,除此之外真的很喜欢解决方案【参考方案2】:

创建一个“索引元组”(编译时整数的元组),然后转发到另一个函数,该函数将索引作为参数包推导出来,并在包扩展中使用它们来调用元组上的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());
  

我对@9​​87654326@ 的实现位于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());

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

【讨论】:

你能解释一下type::template的语法吗? @ubik womble.decadent.org.uk/c++/template-faq.html#disambiguation @JonathanWakely 非常好。也许我错过了一个明显的技巧,但是当有问题的函数是构造函数时,有什么方法可以像这样应用tuple ......还是要求有点太多的魔法? :D 嗯,我想我已经通过在 T_ReturnedObject 上模板化 _impl 等效函数并让它调用该对象的 ctor 并解包所有内容来使其工作。我想这就是我提到的“明显的把戏”! @underscore_d,是的,这是显而易见的方法。

以上是关于C++11:我可以从多个 args 转到 tuple,但我可以从 tuple 转到多个 args 吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C++11元组了解

漂亮的打印 std::tuple

函数之动态参数

如何从 UITableViewController 转到多个视图控制器

boost 是不是支持 c++11 的 std::tuple 的序列化?

python中的*args 和 **kw