Как вы проверяете границы с помощью std span?
std::vector
и почти все другие контейнеры имеют очень удобный способ проверки границ: at()
. std::span
по-видимому, этого нет.
- Почему?
- Есть замена? Помимо развертывания собственного
at()
?
2 ответа
Довольно неуклюже, но примерно так:
- используя позицию
template<class Container>
auto& at(Container&& c, std::size_t pos){
if(pos >= c.size())
throw std::out_of_range("out of bounds");
return c[pos];
}
- с использованием итераторов:
template<class Iterator, class Container>
auto& at(Container&& c, Iterator&& it){
if(std::distance(c.begin(), it) >= c.size())
throw std::out_of_range("out of bounds");
return *it;
}
В документе, который представил span в стандартную библиотеку, говорится:
Контроль дальности и безопасность границ
Все обращения к данным, инкапсулированным диапазоном, концептуально проверяются по диапазону, чтобы гарантировать, что они остаются в пределах диапазона. Что на самом деле происходит в результате несоблюдения ограничений безопасности span во время выполнения, так это неопределенное поведение.
То есть операции имеют узкие контракты, что дает свободу реализации.
Если ваша стандартная библиотека не позволяет вам контролировать поведение до соответствующей степени детализации. gsl-lite предлагает замену с настраиваемым поведением при нарушении контракта. Microsoft GSL ранее конфигурируемый, но в настоящее время всегда заканчивается на нарушение договора, обсуждается здесь (который на самом деле может быть то, что вы хотите).