简体   繁体   中英

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

In python you can do list[2:] to get every element after the second element. Is there any way to do the same thing with an array in c++?

I hope I figured an acceptable answer. Unfortunately in C++, you cannot overload operator[] with more than one argument so I used operator() instead.

#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;
}

Now you could even overload it to accept three arguments to account for the step , just like in Python. I let that as an exercise to you.

Instead of creating a custom class that introduces some amount of maintenance and certain limitations you can use the concept of iterators. Two iterators are used to represent a range of values. For example the function

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

would take a range of objects that is only specified by two iterators. It's a template, so it can take iterators from different containers. To select a sub-range from a range given this way you can use std::next() and std::prev() . For example for a

std::vector<int> list;

you can call foo with a subrange starting from third element as:

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

or call foo with a subrange from the third to the second last element:

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

If you need/want to copy a subrange you can easily do that. For example

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

would create a vector sublist that contains the third to second last element from list .

Of cause those are just simple examples. In a real world application you need to check if those subranges are valid/exist.

The advantages are:

  • no extra wrapper classes
  • no need to copy any data (only the iterators themselves)
  • the standard library works almost exclusively with iterators to represent ranges, so it's good to stick to that concept.
  • With templates you can easily support all containers in the standard library as long as their iterators satisfy the requirements listed in the reference. (You could use the above examples with std::array , std::list and most other containers without any modifications, except for the type of list of cause)
  • iterators are an interface for user or third party containers, as long as they provide iterators that satisfy the requirements listed in the reference.

On the contra side:

  • the code gets a bit more complex
  • it may take some time to understand iterators, because it's a quite different concept than other languages use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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