繁体   English   中英

是否有类似于 python 切片符号的 c++ function ?

[英]Is there a c++ function similar to pythons slice notation?

在 python 中,您可以执行list[2:]以获取第二个元素之后的每个元素。 有没有办法对 c++ 中的阵列做同样的事情?

我希望我能找到一个可以接受的答案。 不幸的是,在 C++ 中,你不能用多个参数重载operator[] ,所以我改用operator()

#include <iostream>
#include <vector>

template <typename T>
class WrapperVector
{
private:
    std::vector<T> data;

public:
    WrapperVector(size_t reserve_size)
    {
        data.reserve(reserve_size);
    }
    WrapperVector(typename std::vector<T>::iterator start, typename std::vector<T>::iterator end)
    {
        data = std::vector<T>(start, end);
    }

    // appends element to the end of container, just like in Python

    void append(T element)
    {
        data.push_back(element);
    }

    /* instead of operator[], operator() must be used
        because operator[] can't accept more than one argument */

    // instead of self[x:y], use this(x, y)

    WrapperVector<T> operator()(size_t start, size_t end)
    {
        return WrapperVector<T>(data.begin() + start, data.begin() + end);
    }

    // instead of self[x:], use this(x)

    WrapperVector<T> operator()(size_t start)
    {
        return WrapperVector<T>(data.begin() + start, data.end());
    }

    // prints all elements to cout

    void print()
    {
        if (!data.size())
        {
            std::cout << "No elements.\n";
            return;
        }
        std::cout << data[0];
        size_t length = data.size();
        for(size_t i=1; i < length; i++)
            std::cout << ' ' << data[i];
        std::cout << '\n';
    }
};

int main()
{
    WrapperVector<int> w(5);
    w.append(1);
    w.append(2);
    w.append(3);
    w.append(4);
    w.append(5);

    w(0).print();
    w(1, 3).print();

    // you can also save the slice
    WrapperVector<int> w2 = w(2);
    WrapperVector<int> w3 = w(2, 4);
    w2.print();
    w3.print();

    return 0;
}

现在您甚至可以重载它以接受三个 arguments 来解释该step ,就像在 Python 中一样。 我把它作为一个练习给你。

您可以使用迭代器的概念,而不是创建引入一些维护和某些限制的自定义 class。 两个迭代器用于表示一系列值。 例如 function

template<typename TIterator>
foo(TIterator start, TIterator end);

将采用仅由两个迭代器指定的对象范围。 它是一个模板,因此它可以从不同的容器中获取迭代器。 到 select 以这种方式给出的范围的子范围,您可以使用std::next()std::prev() 例如对于一个

std::vector<int> list;

您可以使用从第三个元素开始的子范围调用 foo :

foo(std::next(list.begin(), 2), list.end()); 

或使用从第三个到倒数第二个元素的子范围调用 foo:

foo(std::next(list.begin(), 2), std::prev(list.end(), 1));

如果您需要/想要复制子范围,您可以轻松地做到这一点。 例如

std::vector<int> subList(std::next(list.begin(), 2),
                         std::prev(list.end(), 1));

将创建一个向sublist ,其中包含list倒数第三个元素。

当然,这些只是简单的例子。 在现实世界的应用程序中,您需要检查这些子范围是否有效/存在。

优点是:

  • 没有额外的包装类
  • 无需复制任何数据(仅迭代器本身)
  • 标准库几乎只使用迭代器来表示范围,所以最好坚持这个概念。
  • 使用模板,您可以轻松地支持标准库中的所有容器,只要它们的迭代器满足参考中列出的要求。 (您可以将上述示例与std::arraystd::list和大多数其他容器一起使用,无需任何修改,原因list类型除外)
  • 迭代器是用户或第三方容器的接口,只要它们提供满足参考中列出的要求的迭代器。

另一方面:

  • 代码变得有点复杂
  • 理解迭代器可能需要一些时间,因为它与其他语言使用的概念完全不同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM