删除第一种类型的std :: tuple

csc*_*wan 24 c++ c++11 stdtuple

这似乎是一个非常简单的问题:如何删除第一个(第n个)类型std::tuple

例:

typedef std::tuple<int, short, double> tuple1;
typedef std::tuple<short, double> tuple2;
Run Code Online (Sandbox Code Playgroud)

上述操作将转变tuple1tuple2.可能吗?

And*_*owl 28

您可以使用基于类模板的部分特化的简单类型函数:

#include <type_traits>
#include <tuple>

using namespace std;

template<typename T>
struct remove_first_type
{
};

template<typename T, typename... Ts>
struct remove_first_type<tuple<T, Ts...>>
{
    typedef tuple<Ts...> type;
};

int main()
{
    typedef tuple<int, bool, double> my_tuple;
    typedef remove_first_type<my_tuple>::type my_tuple_wo_first_type;

    static_assert(
        is_same<my_tuple_wo_first_type, tuple<bool, double>>::value, 
        "Error!"
        );
}
Run Code Online (Sandbox Code Playgroud)

此外,这个解决方案可以很容易地推广到删除第i类元组:

#include <type_traits>
#include <tuple>

using namespace std;

template<size_t I, typename T>
struct remove_ith_type
{
};

template<typename T, typename... Ts>
struct remove_ith_type<0, tuple<T, Ts...>>
{
    typedef tuple<Ts...> type;
};

template<size_t I, typename T, typename... Ts>
struct remove_ith_type<I, tuple<T, Ts...>>
{
    typedef decltype(
        tuple_cat(
            declval<tuple<T>>(),
            declval<typename remove_ith_type<I - 1, tuple<Ts...>>::type>()
            )
        ) type;
};

int main()
{
    typedef tuple<int, bool, double> my_tuple;
    typedef remove_ith_type<1, my_tuple>::type my_tuple_wo_2nd_type;

    static_assert(
        is_same<my_tuple_wo_2nd_type, tuple<int, double>>::value, 
        "Error!"
        );
}
Run Code Online (Sandbox Code Playgroud)

  • @StoryTeller:模板元编程是一个非常酷的黑客,可以在其他语言中更优雅地解决问题. (6认同)

Jon*_*ely 8

我写了一个被C++ 14标准接受的提议,这使得它很容易为任何"类似元组"的类型做,即支持tuple_sizetuple_elementAPI的类型:

template<typename T, typename Seq>
    struct tuple_cdr_impl;

template<typename T, std::size_t I0, std::size_t... I>
    struct tuple_cdr_impl<T, std::index_sequence<I0, I...>>
    {
        using type = std::tuple<typename std::tuple_element<I, T>::type...>;
    };

template<typename T>
    struct tuple_cdr
    : tuple_cdr_impl<T, std::make_index_sequence<std::tuple_size<T>::value>>
    { };
Run Code Online (Sandbox Code Playgroud)

并且您可以使用几个函数将元组对象转换为新类型:

template<typename T, std::size_t I0, std::size_t... I>
typename tuple_cdr<typename std::remove_reference<T>::type>::type
cdr_impl(T&& t, std::index_sequence<I0, I...>)
{
    return std::make_tuple(std::get<I>(t)...);
}

template<typename T>
typename tuple_cdr<typename std::remove_reference<T>::type>::type
cdr(T&& t)
{
    return cdr_impl(std::forward<T>(t),
                    std::make_index_sequence<std::tuple_size<T>::value>{});
}
Run Code Online (Sandbox Code Playgroud)

这将创建一个整数序列[0,1,2,...,N),其中Ntuple_size<T>::value,然后创建一个新的元组make_tuple(get<I>(t)...)用于I[1,2,...,N)

测试它:

using tuple1 = std::tuple<int, short, double>;
using tuple2 = std::tuple<short, double>;
using transformed = decltype(cdr(std::declval<tuple1>()));
static_assert(std::is_same<transformed, tuple2>::value, "");
static_assert(std::is_same<tuple_cdr<tuple1>::type, tuple2>::value, "");


#include <iostream>

int main()
{
    auto t = cdr(std::make_tuple(nullptr, "hello", "world"));
    std::cout << std::get<0>(t) << ", " << std::get<1>(t) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

我对该提案的参考实现位于https://gitlab.com/redistd/integer_seq/blob/master/integer_seq.h