【问题标题】:How can a type be removed from a template parameter pack?如何从模板参数包中删除类型?
【发布时间】:2014-07-14 09:02:19
【问题描述】:

我正在寻找一种从模板参数包中删除(现在假设所有出现)类型的方法。最终结果将是一个看起来像这样的结构:

template<typename T, typename...Ts>
struct RemoveT
{
    using type = /* a new type out of Ts that does not contain T */
}

假设边缘情况 RemoveT&lt;int, int&gt; 将通过返回 void 来处理(未在下面的代码中处理)。我的最初的设计是这样的

// --------------------------------------------------------------
// 1. A "way" of typedefing variadic number of types ------------
template<typename...Ts>
struct pack { 
    using type = Ts; 
};
// --------------------------------------------------------------

// --------------------------------------------------------------
template<typename T, typename...Ts> struct RemoveT;

template<typename T, typename T1, typename...Ts>
struct RemoveT {
    using type = typename pack<T1, typename RemoveT<T, Ts...>::type>::type;
};

template<typename T, typename T1>
struct RemoveT<T, T1> { 
    using type = T1; 
};

template<typename T, typename...Ts>
struct RemoveT<T, T, Ts...> {
    using type = typename RemoveT<Ts...>::type;
};
// --------------------------------------------------------------

现在我什至无法开始测试这段代码,因为the pack structure is not valid C++

重申

以防万一这对答案有帮助,解决它的其他一些想法

  • 有人可能会说pack 根本没有用。相反,我们可以移动 RemoveT 结构,创建一个仅包含所需类型的新 RemoveT。然后问题转变为从结构中提取类型
  • 我们可以创建模仿 typelists 行为的类型对,并对此采取更递归的方法。

底线

对于可变参数类型 Ts 和类型 T我可以从 Ts 创建 Us 省略 T 吗?

【问题讨论】:

  • 当我在思考这个问题的时候,我很好奇我会被用来做什么。 IE。什么是示例应用程序?
  • @WhozCraig 好点。引用一位伟大的程序员“如果我告诉你,我将不得不杀了你或雇用你”:P ...当然还有好奇心
  • 你是对的,你不能像你在这里概述的那样拥有struct pack。但是您可以使用std::tuple,例如:typedef std::tuple&lt;Ts...&gt; type;,这可能是一种快速获取所需内容的方法。
  • 这似乎很宽泛。您确定您不是在寻找某种描述的留言板或聊天室吗?
  • @DeadMG 没有提到你的名字 man(也没有提到)。我没有直接的抱怨,我只是在回复 Lighness。对任何你认为值得投反对票的东西投反对票是完全可以的,我不需要知道原因。

标签: c++ templates c++11 variadic-templates template-meta-programming


【解决方案1】:

以下提供了一种非递归且直接的方法来从Ts... 中删除T,并且与Jarod42 的解决方案一样,生成std::tuple&lt;Us...&gt;,但无需使用typename ...::type

#include <tuple>
#include <type_traits>

template<typename...Ts>
using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));

template<typename T, typename...Ts>
using remove_t = tuple_cat_t<
    typename std::conditional<
        std::is_same<T, Ts>::value,
        std::tuple<>,
        std::tuple<Ts>
    >::type...
>;


int main()
{
    static_assert(std::is_same<
        remove_t<int, int, char, int, float, int>,
        std::tuple<char, float>
    >::value, "Oops");
}

Live example

【讨论】:

  • 这是一个很好的答案。只是为了记录它并没有在 VS2013 中编译(我承认这并不令人震惊)
【解决方案2】:

以下可能会有所帮助:

namespace detail
{
    template <typename T, typename Tuple, typename Res = std::tuple<>>
    struct removeT_helper;


    template<typename T, typename Res>
    struct removeT_helper<T, std::tuple<>, Res>
    {
        using type = Res;
    };

    template<typename T, typename... Ts, typename... TRes>
    struct removeT_helper<T, std::tuple<T, Ts...>, std::tuple<TRes...>> :
        removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes...>>
    {};

    template<typename T, typename T1, typename ...Ts, typename... TRes>
    struct removeT_helper<T, std::tuple<T1, Ts...>, std::tuple<TRes...>> :
        removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes..., T1>>
    {};

}

template <typename T, typename...Ts> struct RemoveT
{
    using type = typename detail::removeT_helper<T, std::tuple<Ts...>>::type;
};

static_assert(std::is_same<std::tuple<char, float>,
                        typename RemoveT<int, int, char, int, float, int>::type>::value, "");

【讨论】:

    【解决方案3】:

    首先,将所有特定模板名称移到一个列表中。可能有一种方法可以指定模板名称和参数列表,并为该模板提供参数,但我无法弄清楚:

    template <typename...TArgs> struct TypeList
    {
        typedef std::tuple<TArgs...> tuple_type;
        // whatever other types you need
    };
    

    接下来,定义加法:

    template<typename T, typename TList> struct AddT;
    
    template<typename T, typename ... TArgs>
    struct AddT< T, TypeList<TArgs...> >
    {
        typedef TypeList<T, TArgs... > type;
    };
    

    然后,定义移除:

    template<typename R, typename ... TArgs> struct RemoveT;
    
    template<typename R>
    struct RemoveT<R>
    {
        typedef TypeList<> type;
    };
    
    template<typename R, typename T, typename ...TArgs>
    struct RemoveT<R, T, TArgs...>
    {
        typedef typename std::conditional
            < std::is_same<R, T>::value
            , typename RemoveT<R, TArgs...>::type
            , typename AddT<T, typename RemoveT<R, TArgs...>::type>::type
            >::type type;
    };
    

    最后,测试:

    int result = 0;
    result = std::is_same
        < std::tuple<long,double>
        , RemoveT<int, int, long, int, double, int>::type::tuple_type
        >::value;
    assert ( result );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-10
      • 1970-01-01
      • 2019-09-01
      • 2016-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多