Я хочу получить диапазон элементов из std::vector<MyClass>
и сохранить их как константные ссылки, потому что я хочу только читать, но не изменять их.
#include <iostream>
#include <vector>
// a "large" user class
class MyClass {
public:
int data;
MyClass(int val) : data(val) {}
};
int main() {
// Initialize vector to MyClass objects
std::vector<MyClass> myClass{1, 2, 3, 4, 5, 6, 7, 8};
// Get const reference to element with index 0
const auto &el = myClass[0];
// Get const references to a range of elements
const unsigned int start = 1, end = 4;
// const auto &elRange = ???
return 0;
}
Как я могу добиться чего-то подобного в c++17
или ниже?
С какой проблемой вы столкнулись?
Похоже, вам просто нужна пара const_iterator
: const auto elRangeBegin = myClass.cbegin() + 1; const auto elRangeEnd = myClass.cbegin() + 4;
const auto elRange = std::span(&myClass[1], &myClass[4]);
Я забыл упомянуть. у меня только с++17
Напишите собственный класс представления, в котором вы не хотите использовать индексы и арифметику.
@Mathieu, тогда отредактируй свой вопрос и четко изложи это, чтобы все это заметили.
Для этого и создан std::span, но для этого вам понадобится C++20.
Если вы застряли на младших версиях C++, вы можете использовать boost::span. (Для включения в проект требуется 2 заголовка, вам не нужна вся библиотека повышения)
auto elements = boost::span<const MyClass>{myClass}.subspan(start, end-start);
Я хочу получить диапазон элементов из std::vector и сохранить их как константные ссылки, потому что я хочу только читать, но не изменять их.
Лучше всего использовать std::span , для которого требуется поддержка C++20.
В противном случае вы пишете для этого простой SimpleSpan
класс. Так же просто, как:
// A simple span-like class for C++17
template<typename T>
class SimpleSpan
{
T* data_;
std::size_t size_;
public:
constexpr SimpleSpan(T* data, std::size_t size) : data_{ data }, size_{ size } {}
constexpr T& operator[](std::size_t index) { return data_[index]; }
constexpr T& operator[](std::size_t index) const { return data_[index]; }
constexpr T* begin() { return data_; }
constexpr T* end() { return data_ + size_; }
constexpr T* begin() const { return data_; }
constexpr T* end() const { return data_ + size_; }
constexpr std::size_t size() const { return size_; }
};
и просто
// Get const references to a range of elements using our SimpleSpan
const unsigned int start = 1, end = 4;
SimpleSpan<const MyClass> elRange(&myClass[start], end - start);
Разве нам не нужно писать деструктор этого класса? Поскольку SimpleSpan
имеет необработанный указатель в качестве члена
@Матье, класс не владеет данными и не управляет ими. Что бы вы поместили в предложенный вами деструктор?
@Mathieu Std::span/ SimpleSpan — это представление непрерывной последовательности объектов, не являющееся владельцем. Он не управляет никакими ресурсами напрямую. Он спроектирован так, чтобы быть простым и легким, без необходимости индивидуального управления ресурсами. Поэтому нет необходимости в правиле 3/5!
То же самое касается ссылок/указателей/представлений векторов. Вам не следует их где-либо хранить (просто используйте их локально). Одна модификация базового вектора может привести к перераспределению, и тогда ваше представление перестанет быть действительным.
Вы можете использовать std::span, если можете перейти на C++20, или просто сохранить индексы в новом векторе.