整数参数特殊值的模板特化

时间:2015-09-14 17:11:43

标签: c++ templates c++11 c++14 template-specialization

我正在努力使用整数参数的模板特化,也许这根本不可能?

我尝试了什么:

template< int COUNT, typename REMOVE, typename ...T>
struct RemoveFirstElementsImpl
{
    using Type= typename RemoveFirstElementsImpl<COUNT-1, T...>::Type;
};

template< typename ...T>
struct RemoveFirstElementsImpl<0, T...>
{
    using Type= TypeContainer<T...>;
};


template < int COUNT, typename ... T >
struct RemoveFirstElements
{
    using Type = typename RemoveFirstElementsImpl< COUNT, T...>::Type;
};

结果

  

错误:部分特化并不比主模板更专业化,因为它用包扩展替换了多个参数

然后我想到了SFINAE:

template < int COUNT, typename = typename std::enable_if<COUNT==0>::type, typename HEAD, typename ... T >
struct RemoveFirstElements
{
    using Type= TypeContainer<T...>;
};
template < int COUNT, typename = void, typename HEAD, typename ... T >
struct RemoveFirstElements
{
    using Type= RemoveFirstElements<COUNT-1, T...>
};

但我不知道如何运行参数包和默认参数的组合。

也许我完全错了。我想要实现的是获取一个参数列表,其中从我的TypeContainer中删除前n个参数,这只是一个扩展的std :: tuple。我只需要类型本身而不是任何参数,我只需要在类型而不是任何对象上。

2 个答案:

答案 0 :(得分:3)

我想你想要:

template<int COUNT, typename ...Ts> struct RemoveFirstElementsImpl;

template<>
struct RemoveFirstElementsImpl<0>
{
    using type = std::tuple<>;
};

template<typename T, typename ...Ts>
struct RemoveFirstElementsImpl<0, T, Ts...>
{
    using type = std::tuple<T, Ts...>;
};

template<int N, typename T, typename ...Ts>
struct RemoveFirstElementsImpl<N, T, Ts...>
{
    using type = typename RemoveFirstElementsImpl<N - 1, Ts...>::type;
};

Live Demo

答案 1 :(得分:2)

错误说明了一切:

  

部分特化并不比主模板更专业化,因为它用包扩展替换了多个参数

部分专业化必须比主要专业化更专业化。在您的情况下,我们有一个更专业的元素(0 vs COUNT)和一个不太专业的元素Ts... vs T, Ts...专业化至少是专门的每个参数对。

所以我们可以为你的基本情况添加两个特化:

template <int, typename...> struct RemoveFirstElementsImpl;

// base case 1
template <>
struct RemoveFirstElementsImpl<0>
{
    using type = TypeContainer<>; // prefer lower-case type
};

// base case 2
template <typename T, typename... Ts>
struct RemoveFirstElementsImpl<0, T, Ts...>
{
    using type = TypeContainer<T, Ts...>;
};

// recursive case
template <int COUNT, typename T, typename... Ts>
struct RemoveFirstElementsImpl<COUNT, T, Ts...>
: RemoveFirstElementsImpl<COUNT-1, Ts...>
{ };

这有效,但它并不令人满意。让我们选择一种不同的方法。实际上,我们可以随时弹出元素:

template <int COUNT, typename TC>
struct RemoveFirstElementsImpl
: RemoveFirstElementsImpl<COUNT-1, tail_t<TC>>
{ };

template <typename TC>
struct RemoveFirstElementsImpl<0, TC>
{
    using type = TC;
};

或者我们可以使用index_sequence进行一次迭代:

template <int COUNT, typename... Ts>
struct RemoveFirstElementsImpl
: RemoveFirstElementsImpl2<COUNT, TypeContainer<Ts...>,
                           std::make_index_sequence<sizeof...(Ts) - COUNT>
{ };

使用:

template <int COUNT, typename TC, typename Seq>
struct RemoveFirstElementsImpl2;

template <int COUNT, typename TC, size_t... Is>
struct RemoveFirstElementsImpl2<COUNT, TC, std::index_sequence<Is...>>
{
    using type = TypeContainer<get_nth_t<Is+COUNT, TC>...>;
};

get_nth_t<N, TC>是要实现的元函数,返回给定N中的TypeContainer类型。示例实现可能是:

template <int N, typename TC>
struct get_nth;

template <int N, typename TC>
using get_nth_t = typename get_nth<N, TC>::type;

template <int N, typename... Ts>
struct get_nth<N, TypeContainer<Ts...>> {
    using type = std::tuple_element_t<N, std::tuple<Ts...>>;
};