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:
std::array
, std::list
and most other containers without any modifications, except for the type of list
of cause) On the contra side:
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.