【问题标题】:template specialization for special value of integer parameter整数参数特殊值的模板特化
【发布时间】:2015-09-14 17:11:43
【问题描述】:

我正在为整数参数的模板特化而苦苦挣扎,也许这根本不可能?

我尝试了什么:

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...>
};

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

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

【问题讨论】:

  • 请勿丢弃typename REMOVE
  • @DieterLücking 我还在挣扎!你的评论是什么意思。我无法让我的代码再次添加 REMOVE。
  • 看@Jarod42的回答
  • 好的,抓住重点……!谢谢

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


【解决方案1】:

我想你想要:

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

【讨论】:

  • 是的!我现在可以运行了。谢谢!
【解决方案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&lt;N, TC&gt; 是一个要实现的元函数,它返回给定TypeContainer 中的Nth 类型。示例实现可能是:

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...>>;
};

【讨论】:

  • tuple_element_t 效率很低。
  • @T.C.这只是所介绍的三种解决方案之一的示例实现。
  • 谢谢!我仍然看不到您的第一个添加如何适合我的代码。我无法编译它。您可以将其余部分添加到您的第一个示例中吗?我仍然只有无穷无尽的错误列表...
  • @Klaus 添加了RemoveFirstElementsImpl的完整模板
  • @Klaus 为什么不呢?有什么错误?这也和Jarod42's answer一样
猜你喜欢
  • 1970-01-01
  • 2015-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
  • 2017-10-15
  • 1970-01-01
相关资源
最近更新 更多