35

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

在 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))的,因为我想在一个不知道 args 数量的模板中执行此操作。

更完整的例子:

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 的模板,另一个适用于两个的模板,等等……</p>

4

2 回答 2

60

尝试这样的事情:

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

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

于 2012-05-26T12:56:56.077 回答
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_tuplehttps://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());

一个类似的实用程序std::index_sequence在 C++14 中被标准化(参见index_seq.h以了解独立的 C++11 实现)。

于 2012-05-26T15:23:26.693 回答