#c #c 17 #stdstring #string-view
Вопрос:
Можно легко создать а std::string_view
из std::string
а. Но если я хочу создать строковое представление диапазона std::string
, использование итераторов std::string
не работает.
Вот код, который я попробовал: https://gcc.godbolt.org/z/xrodd8PMq
#include <iostream>
#include <string>
#include <string_view>
#include <iterator>
int main()
{
std::string str{"My String"};
std::string_view strView{str}; // works
//std::string_view strSubView{str.begin(), str.begin() 2}; // error
}
Конечно , возможно, мы можем сделать подстроку из str
и использовать для создания строкового представления strSubView
, но есть дополнительное создание строки.
Я обнаружил, что std::basic_string_view
пятый конструктор s принимает диапазон итераторов.
template<class It, class End>
constexpr basic_string_view(It first, End last);
Но являются ли это только итераторами std::string
или просто std::basic_string_view
самим собой? Если бы не std::string
итерации, почему бы нам не иметь его, в конце концов, строковое представление:
описывает объект, который может ссылаться на постоянную непрерывную последовательность объектов, похожих на символы !
Принимая диапазон непрерывной последовательности символов, разве мы не должны считать?
Комментарии:
1. Этот конструктор добавлен в C 20. Если вы компилируете с помощью компилятора C 17, то его нет. Это работает, если вы ориентируетесь на C 20
2.также можно создавать подстроки
std::string_view
«мы можем сделать подстроку из str… но есть создание дополнительной строки»..strSubView = strView.substr( 0, 2 );
. Это было бы сопоставимо с тем, что вы пытаетесь сделать.3. @Caleth О да, это было прямо у меня перед глазами, но я не заметил языковой тег в cppreference. Это означает, что в C 17 нет способа сделать это??
Ответ №1:
Этот конструктор добавлен в C 20. Если вы компилируете с помощью компилятора C 17, то его нет.
Вы можете написать функцию, которая делает то же самое
std::string_view range_to_view(std::string::iterator first, std::string::iterator last) {
return first != last ? { first.operator->(), last - first } : { nullptr, 0 };
}
Комментарии:
1. Я надеюсь, что std::string_view будет встроен в то место, где я когда-либо вызывал
range_to_view
?2. @Const это нематериализованный временный объект, он создается на месте на месте вызова
3. В случае, если
first
точки заканчиваются,operator->
произойдет сбой4. @DmytroOvdiienko нет, вы получите указатель на один конец
5. В теле
operator->()
STL MSVC есть проверка, которая приведет к сбою приложения в случае, если вы попытаетесь вызвать эту функцию поend
указателю. И g не удается его скомпилировать godbolt.org/z/fGxfnoxhd
Ответ №2:
Почему я не могу создать std::string_view из итераторов std::string?
Вы можете, но только начиная с C 20.
Но являются ли это только итераторами строки std::или просто самой строкой std::basic_string_view?
Это любые непрерывные итераторы соответствующего типа значений. Принимаются как итераторы строк, так и итераторы строкового представления. Точные ограничения перечислены в документации.
Это означает, что в C 17 нет способа сделать это??
Невозможно использовать несуществующий конструктор, но есть несколько способов получить желаемое строковое представление. Вот один из них:
std::string_view strSubView = strView.substr(0, 2);
или без промежуточной переменной:
std::string_view strSubView = std::string_view{str}.substr(0, 2);
или если у вас есть только эти итераторы и у вас нет возможности получить доступ к строке:
std::string_view strSubView {amp;*first, last - first};
Комментарии:
1. Спасибо за объяснение, я предпочитаю вспомогательную функцию, пока не смогу использовать C 20.
2.
amp;*first
может произойти сбой, еслиfirst
указывает наend
3.
amp;*first
это то жеfirst.operator->()
самое, что и в ответе Калета, верно?4. @Peter-Восстановите монику Эффективно, да.
Ответ №3:
Поскольку разыменование итератора небезопасно (т. Е. Вызов operator*
итератора и operator->
на итераторе, который указывает на конец, может привести к сбою вашего приложения), единственный способ в C 17, который я вижу, — это вызывать string_view::substr()
и использовать итераторы только для вычисления размера и индекса.
constexpr std::string_view make_string_view(std::string_view str,
std::string_view::iterator first,
std::string_view::iterator last) noexcept
{
return str.substr(first - str.begin(), last - first);
}
И для std:string
использования std::string::data()
в качестве начального указателя.
std::string_view make_string_view(std::string constamp; str,
std::string::const_iterator first,
std::string::const_iterator last) noexcept
{
return std::string_view(str.data() (first - str.begin()), last - first);
}