8

我正在尝试删除元组的最后一个元素。当我在元组中只有一个元素要删除时,它可以工作。但是当我有多个时,事情就会出错。我不明白为什么这不起作用。这些是我得到的错误:

prog.cpp:在函数“<code>int main()”中:
prog.cpp:24:22:错误:不完整的类型“<code>remove_last<std::tuple<int, int>>”在嵌套名称说明符中使用prog.cpp:24:22:错误:嵌套名称说明符 prog.cpp:24:70
中使用的不完整类型 '<code>remove_last<std::tuple<int, int> >' :错误:模板参数 1 无效

#include <tuple>
#include <type_traits>

template <class T>
struct remove_last;

template <class T>
struct remove_last<std::tuple<T>>
{
    using type = std::tuple<>;
};

template <class... Args, typename T>
struct remove_last<std::tuple<Args..., T>>
{
    using type = std::tuple<Args...>;
};

int main()
{
    std::tuple<int, int> var;

    static_assert(
        std::is_same<remove_last<decltype(var)>::type,
        std::tuple<int>>::value, "Values are not the same"
    );
}

当我在其中一种专业化中使模板参数为非可变参数时,错误就消失了。但后来这变成了一种专业化,它只会处理一个包含两个元素的元组——而不是我的目标。我怎样才能让它可变参数一起工作?换句话说,当元组中有多个元素时,我怎样才能让它工作?

4

2 回答 2

6

问题是参数包是贪婪的,并且 - 因为它首先出现 - 在执行类型推导时会吃掉序列中的所有类型,包括T您希望被排除在Args....

您可以通过这种方式定义可变参数特化(请注意,参数包现在最后出现在 中std::tuple<T, Args...>):

template <class T, class... Args>
struct remove_last<std::tuple<T, Args...>>
{
    using type = typename concat_tuple<
        std::tuple<T>,
        typename remove_last<std::tuple<Args...>>::type
        >::type;
};

并以concat_tuple这种方式定义元函数:

template<typename, typename>
struct concat_tuple { };

template<typename... Ts, typename... Us>
struct concat_tuple<std::tuple<Ts...>, std::tuple<Us...>>
{
    using type = std::tuple<Ts..., Us...>;
};
于 2013-04-28T21:48:11.560 回答
1

另一种解决方案,需要 C++14 或更高版本:

#include <tuple>

template<class Tuple>
struct remove_last;

template<>
struct remove_last<std::tuple<>>; // Define as you wish or leave undefined

template<class... Args>
struct remove_last<std::tuple<Args...>>
{
private:
    using Tuple = std::tuple<Args...>;

    template<std::size_t... n>
    static std::tuple<std::tuple_element_t<n, Tuple>...>
        extract(std::index_sequence<n...>);

public:
    using type = decltype(extract(std::make_index_sequence<sizeof...(Args) - 1>()));
};

template<class Tuple>
using remove_last_t = typename remove_last<Tuple>::type;

请参阅https://en.cppreference.com/w/cpp/utility/integer_sequence

于 2018-08-12T02:58:14.747 回答