首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从元组中删除第n个元素?

如何从元组中删除第n个元素?
EN

Stack Overflow用户
提问于 2020-02-18 21:06:11
回答 3查看 465关注 0票数 3

我试图编写一个函数,通过跳过给定索引上的元素,从现有的std::tuple中创建一个新的one。例如:

我有一个元组t定义如下:

代码语言:javascript
复制
constexpr auto t = std::tuple(1, 2, 3, 4);

我想把它复制到另一个元组。但是,我想跳过n元素。假设在本例中,我想跳过的n元素是3(这意味着我希望跳过索引2的元素)。这将导致一个新的元组定义为:

代码语言:javascript
复制
std::tuple(1, 2, 4);

这是我到现在为止最接近的:

代码语言:javascript
复制
template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
    return std::tuple((is != N ? std::get<is>(tp) : 0) ...);
}

template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
    constexpr auto t = std::tuple(elems...);
    return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof...(elems)>());
}

但是,我没有删除n元素,而是将其设置为0。

理想情况下,我将更改函数fun()中的返回参数,以便使用多个临时元组创建一个新的元组:

代码语言:javascript
复制
return std::tuple_cat((is != N ? std::tuple(std::get<is>(tp)) : std::tuple()) ...);

但是,这方面的问题是,三元操作符必须在两边都有匹配类型。

我尝试过的另一种方法是基于递归:

代码语言:javascript
复制
template<std::size_t N, std::size_t head, std::size_t... tail>
constexpr auto fun3() noexcept {
    if constexpr(!sizeof...(tail))
        return std::tuple(head);

    if constexpr(sizeof...(tail) - 1 == N)
        return std::tuple_cat(fun3<N, tail...>());

    if constexpr(sizeof...(tail) - 1 != N)
        return std::tuple_cat(std::tuple(head), fun3<N, tail...>());
}

然而,这甚至是不成功的。在本例中,如果N等于0,则在新元组中仍将使用n元素(这也是这里的第一个元素)。而且,这甚至不会编译,因为第二条语句有一个问题:

代码语言:javascript
复制
if constexpr(sizeof...(tail) - 1 == N)

我在这里错过了什么?如何在复制过程中复制元组并跳过其元素之一?

我正在使用C++17,我需要在编译时对函数进行评估。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-02-18 21:23:36

关于

代码语言:javascript
复制
return std::tuple_cat( foo<is, N>::func(std::get<is>(tp)) ...);

其中foo是一个具有专门化的结构,如下所示?

代码语言:javascript
复制
template <std::size_t, std::size_t>
struct foo
 {
   template <typename T>
   static auto func (T const & t)
    { return std::make_tuple(t); } 
 }

template <std::size_t N>
struct foo<N, N>
 {
   template <typename T>
   static std::tuple<> func (T const &)
    { return {}; } 
 }

(警告:未经测试的代码)。

这几乎是您的三元操作符的概念,但是没有匹配两边类型的问题:只有正确的类型被实例化。

票数 3
EN

Stack Overflow用户

发布于 2020-02-18 21:42:02

另一种解决方案是创建两个索引序列,它们引用元组的前后部分。

代码语言:javascript
复制
template<std::size_t nth, std::size_t... Head, std::size_t... Tail, typename... Types>
constexpr auto remove_nth_element_impl(std::index_sequence<Head...>, std::index_sequence<Tail...>, std::tuple<Types...> const& tup) {
    return std::tuple{
        std::get<Head>(tup)...,
        // We +1 to refer one element after the one removed 
        std::get<Tail + nth + 1>(tup)...
    };
}

template<std::size_t nth, typename... Types>
constexpr auto remove_nth_element(std::tuple<Types...> const& tup) {
    return remove_nth_element_impl<nth>(
        std::make_index_sequence<nth>(), // We -1 to drop one element 
        std::make_index_sequence<sizeof...(Types) - nth - 1>(),
        tup
    );
}

下面是对此函数的测试:

代码语言:javascript
复制
int main() {
    constexpr auto tup = std::tuple{1, 1.2, 'c'};
    constexpr auto tup2 = remove_nth_element<0>(tup);
    constexpr auto tup3 = remove_nth_element<2>(tup);
    static_assert(std::is_same_v<decltype(tup2), const std::tuple<double, char>>);
    static_assert(std::is_same_v<decltype(tup3), const std::tuple<int, double>>);
    return 0;
}

实例化

该解决方案具有不构造中间元组和不使用std::tuple_cat的优点,这两者在编译时间上都很困难。

票数 2
EN

Stack Overflow用户

发布于 2020-02-18 21:26:34

在贴出问题的几分钟后,我找到了一个解决办法。不太理想,但嘿:

代码语言:javascript
复制
template<std::size_t N, typename T, std::size_t ... is>
constexpr auto fun(T&& tp, std::index_sequence<is...>&& i) noexcept {
    return std::tuple((is < N ? std::get<is>(tp) : std::get<is+1>(tp)) ...);
}

template<std::size_t N, std::size_t... elems>
constexpr auto fun2() noexcept {
    constexpr auto t = std::tuple(elems...);
    return fun<N>(std::forward_as_tuple(elems...), std::make_index_sequence<sizeof... (elems) - 1>());
}

这样,我们在nth元素之前复制所有元素,当我们到达nth元素时,我们增加1的下一个索引。我们不会超出范围,因为我们传递的index_sequence比传递的元组少一个元素。

我希望这个答案能对某人有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60289471

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档