2012-05-26 39 views
29

可能重复:
How do I expand a tuple into variadic template function's arguments?
“unpacking” a tuple to call a matching function pointerC++ 11:我可以从多个参数去元组,但我可以从元组去多个参数吗?

在C++ 11层的模板,有使用一个元组作为一个(可能是模板)功能的个人ARGS的方法吗?

例:
比方说,我有这样的功能:

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的作品,另一种为两部作品,等等

+3

当然。你需要像'template call(F f,Tuple const&t){f(std :: get (t)...); }'。现在只需填入空格:-) –

+0

您的意思是跳过可变参数模板并创建多个'caller()'模板? – Thomas

+0

@Thomas:你将不得不做一个小小的调度工具来建立整数包'N ...',并且部分专精于'N == std :: tuple_size :: value',你想调用原来的功能,我建议的方式。 –

回答

55

试试像这样:

// 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,你也可以使整个事情返回正确的返回值。

+6

作为模板手淫练习,这很好,但是你真的想写'call_impl :: value,std :: tuple_size :: value> :: call(f,std :: forward (t))'你想扩展一个元组的任何地方? –

+9

@JonathanWakely:'call_impl'是一个实现细节 - 用户永远不会直接调用它,全局'call'就是所有的用户接口。这个例子不清楚吗? – ildjarn

+0

啊不,我只是没有看好,我认为'call'是OP的'caller'的替代品,所以在用户的​​代码中使用'call_impl'笨拙地使用。 –

4

创建一个“索引记录”(编译时整数的元组),然后前进到推导出指数作为参数包,并使用他们的包扩展调用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()); 
    } 

我的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()); 

在C++ 14中将类似的工具标准化为std::index_sequence(有关独立C++ 11实现,请参阅index_seq.h)。

+0

你能解释'type :: template'语法吗? – ubik

+0

@ubik https://womble.decadent.org.uk/c++/template-faq.html#disambiguation –

+0

@JonathanWakely非常好。也许我错过了一个显而易见的窍门,但当有问题的函数是一个构造函数时,是否有任何方法可以像这样应用'tuple' ...还是要求一点魔法? :D –

相关问题