来自元组的构造函数参数

时间:2013-02-15 15:06:59

标签: c++ templates c++11 constructor stdtuple

假设我有一个模板,它由类类型和许多参数类型进行参数化。匹配这些类型的一组参数存储在元组中。如何将这些传递给类类型的构造函数?

几乎是C ++ 11代码:

template<typename T, typename... Args>
struct foo {
  tuple<Args...> args;
  T gen() { return T(get<0>(args), get<1>(args), ...); }
};

如何在不修复长度的情况下填充构造函数调用中的...

我想我可以想出一些复杂的递归模板调用机制来做到这一点,但是我不敢相信我是第一个想要它的人,所以我想有一些现成的解决方案可以使用在那里,甚至可能在标准库中。

5 个答案:

答案 0 :(得分:5)

您需要一些模板元编程机制才能实现这一目标。

实现参数调度的最简单方法是在包含编译时整数序列的表达式上利用包扩展。需要使用模板机制来构建这样的序列(有关标准化此类序列的建议的更多信息,请参阅本答案末尾的注释)。

假设有一个类(模板)index_range封装编译时整数范围[M,N]和一个类(模板)index_list,它封装了一个编译时的整数列表,这就是你如何使用它们:

template<typename T, typename... Args>
struct foo
{
    tuple<Args...> args;

    // Allows deducing an index list argument pack
    template<size_t... Is>
    T gen(index_list<Is...> const&)
    {
        return T(get<Is>(args)...); // This is the core of the mechanism
    }

    T gen()
    {
        return gen(
            index_range<0, sizeof...(Args)>() // Builds an index list
            );
    }
};

以下是index_rangeindex_list的可能实施方式:

//===============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS

// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};

// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
    // Declare primary template for index range builder
    template <size_t MIN, size_t N, size_t... Is>
    struct range_builder;

    // Base step
    template <size_t MIN, size_t... Is>
    struct range_builder<MIN, MIN, Is...>
    {
        typedef index_list<Is...> type;
    };

    // Induction step
    template <size_t MIN, size_t N, size_t... Is>
    struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
    {
    };
}

// Meta-function that returns a [MIN, MAX) index range
template<unsigned MIN, unsigned MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;

另请注意,interesting proposal Jonathan Wakely存在{strong>标准化 int_seq类模板,这与我所谓的{{1}非常相似这里。

答案 1 :(得分:4)

C ++ 17为此std::make_from_tuple

template <typename T, typename... Args>
struct foo
{
  std::tuple<Args...> args;
  T gen() { return std::make_from_tuple<T>(args); }
};

答案 2 :(得分:3)

C ++ 14将为index_sequence添加标准支持:

template<typename T, typename... Args>
struct foo {
  tuple<Args...> args;
  T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
private:
  template <size_t... Indices>
  T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
};

答案 3 :(得分:1)

创建从0到n-1的索引序列:

template<size_t... indexes>
struct seq {};

template<size_t n, size_t... indexes>
struct make_seq: make_seq<n-1, n-1, indexes...> {};

template<size_t... indexes>
struct make_seq: make_seq<0, indexes...> {
  typedef seq<indexes...> type;
};

与你的args并行解压缩,或者作为你get<>的索引。

目标如下:

template< typename T, typename Tuple, typename Indexes >
struct repack;

template< typename... Ts, size_t... indexes >
struct repack< tuple<Ts...>, seq<indexes...> > {
  T operator()( tuple<Ts...> const& args ) const {
    return T( get<indexes>(args)... );
  }
};

repack中使用gen,如下所示:

T gen() {
  repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
  return repacker( args );
}    

答案 4 :(得分:1)

您需要使用indices trick,这意味着一层间接:

template <std::size_t... Is>
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 T, typename... Args>
struct foo {
  tuple<Args...> args;
  T gen() { return gen(build_indices<sizeof...(Args)>{}); }
private:
  template<std::size_t... Is>
  T gen(indices<Is...>) { return T(get<Is>(args)...); }
};