模板定义的模板参数数量非常中继

问题描述

template<int Degree> using curve = // some deFinition
template<int MaxDegree> using curve_variant = std::variant<curve<1>,curve<2>,.. curve<MaxDegree>>;

在上面的示例中,传递给std :: variant模板的参数数量将根据curve_variant的参数而变化: 例如,curve_variant<4>将解析为std::variant<curve<1>,curve<3>,curve<4>>

由于MaxDegree在编译时是已知的,因此这是有可能的。但是我也不知道如何开始执行此操作。

解决方法

借助std::integer_sequence助手,您可以这样做:

template <typename Seq> struct curve_variant_impl;

template <int ... Is>
struct curve_variant_impl<std::integer_sequence<int,Is...>>
{
    using type = std::variant<curve<1 + Is>...>;
}; 

template <int MaxDegree>
using curve_variant = typename curve_variant_impl<std::make_integer_sequence<int,MaxDegree>>::type;
,

其他答案表明std::integer_sequence是一个很好的工具。假设我们没有。

以下内容仅是说明如果没有std::integer_sequence,我们将必须编写哪些代码。实际上,没有理由用这种方式编写它,如果没有C ++ 14,则可以很容易地重新实现。

#include <variant>
#include <type_traits>


template<int Degree> struct curve{};

// helper to add a type to a variant
template <typename A,typename... others>
struct merge_variants {
    using type = std::variant<others...,A>;
};

template <typename A,typename... others>
struct merge_variants<A,std::variant<others...>> : merge_variants<A,others...> {};

// the recursion:
template <int MaxDegree>
struct Foo {
    using type = typename merge_variants< curve<MaxDegree>,typename Foo<MaxDegree-1>::type >::type;
};

// the base case:
template <>
struct Foo<1> {
    using type = std::variant< curve<1> >;
};


int main() {
    static_assert(std::is_same<std::variant<curve<1>,curve<2>,curve<3>>,Foo<3>::type >::value);
}

要实例化Foo<N>(对不起,此名称)N,递归是相当昂贵的,即使我们从未要求过其他类型也必须实例化。 std::integer_sequence可以完全避免递归。

,
#include <utility>
#include <variant>
template<int Degree>
struct curve{};

template<typename index_seq>
struct curve_variant_impl;

template<int...indices>
// Start binding indices from 1,not zero
struct curve_variant_impl<std::integer_sequence<int,indices...>>{
    using type = std::variant<curve<indices>...>;
};


template<int MaxDegree>
//make_integer_sequence makes [0,MaxDegree),we want [1,MaxDegree]
using curve_variant = typename curve_variant_impl<std::make_integer_sequence<int,MaxDegree+1>>::type;
int main() {
   static_assert(std::is_same_v<curve_variant<4>,std::variant<curve<1>,curve<3>,curve<4>>>);
}

以上仅适用于非负值,因此您最好使用std::size_t,它是索引的自然类型。

,

只需回答其他答案,如果您拥有C ++ 11但没有C ++ 14,则可以使用一个巧妙的技巧来模拟std :: integer_sequence:

template <int...>
struct seq { };

template <int N,int... S>
struct gens : gens<N - 1,N - 1,S...> { };

template <int... S>
struct gens<0,S...> {
    typedef seq<S...> type;
};

在这种模式下,gens的运行方式与integer_sequence相同。 gens<N>::typeseq<1,2,3,...,N>。因此,您使用它的方式相同

template <typename T>
struct make_curve_variant_impl

template <int... N>
struct make_curve_variant_impl<seq<N...>>
{
    typef std::variant<curve<N+1>...> type;
};

template <typename N>
struct make_curve_variant
{
    typedef make_curve_variant_impl<typename gens<N>::type>:: type;
};