Нередко приходится выполнять стандартные алгоритмы для
C-строк.
Чтобы предоставить два итератора, начальный итератор и конечный итератор диапазона, то есть начало и конец строки, для алгоритма приходится вызывать стандартную C-функцию
strlen, объявленную в заголовочном файле
<cstring>. Например, вызов стандартного алгоритма
std::adjacent_find, содержащего строку, может выглядеть следующим образом
size_t n = ::strlen( s );
char *p = std::adjacent_find( s, s + n );
if ( p != s + n ) std::cout << p << std::endl;
Как видно из примера, требуется вызывать стандартную C-функцию
strlen, чтобы получить конечный итератор диапазона.
Однако все C-строки по определению имеют завершающий ноль-символ
'\0', и по этому символу легко определить конец диапазона, если имеешь дело с последовательными итераторами. То есть предварительный вызов функции
strlen является неэффективным и избыточным.
В связи с этим я предлагаю использовать итераторы, названные мною как
const_c_str_iterator и
c_str_iterator, которые позволяют применять стандартные алгоритмы к
C-строкам без необходимости вызова стандартной C-функции
strlen, чтобы задать диапазон итераторов.
Ниже приведена демонстрационная программа, в которой показано, как данные итераторы для
C-строк могут быть определены.
#include <iostream>
#include <iterator>
#include <algorithm>
class const_c_str_iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = char;
using difference_type = ptrdiff_t;
using pointer = const char *;
using reference = const char &;
// Constructors
const_c_str_iterator() = default;
explicit const_c_str_iterator( const char *s ) : s( s )
{
}
const_c_str_iterator( const const_c_str_iterator & ) = default;
// The copy assignment operator
const_c_str_iterator & operator =( const const_c_str_iterator &it )
{
this->s = it.s;
return *this;
}
// Conversion operator
operator pointer() const
{
return s;
}
// Increment operators
const_c_str_iterator & operator ++()
{
++this->s;
return *this;
}
const_c_str_iterator operator ++( int )
{
const_c_str_iterator it( this->s );
++this->s;
return it;
}
// Dereferencing operator
reference operator *() const
{
return *s;
}
friend bool operator ==( const const_c_str_iterator &it1, const const_c_str_iterator &it2 );
friend bool operator !=( const const_c_str_iterator &it1, const const_c_str_iterator &it2 );
protected:
const char *s = nullptr;
};
bool operator ==( const const_c_str_iterator &it1, const const_c_str_iterator &it2 )
{
return ( it1.s == it2.s ) || ( not it1.s && not *it2.s ) || ( not *it1.s && not it2.s );
}
bool operator !=( const const_c_str_iterator &it1, const const_c_str_iterator &it2 )
{
return not ( it1 == it2 );
}
class c_str_iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = char;
using difference_type = ptrdiff_t;
using pointer = char *;
using reference = char &;
// Constructors
c_str_iterator() = default;
explicit c_str_iterator( char *s ) : s( s )
{
}
c_str_iterator( const c_str_iterator & ) = default;
// The copy assignment operator
c_str_iterator & operator =( const c_str_iterator &it )
{
this->s = it.s;
return *this;
}
// Conversion operators
operator pointer() const
{
return s;
}
operator const_c_str_iterator() const
{
return const_c_str_iterator( this->s );
}
// Increment operators
c_str_iterator & operator ++()
{
++this->s;
return *this;
}
c_str_iterator operator ++( int )
{
c_str_iterator it( this->s );
++this->s;
return it;
}
// Dereferencing operator
reference operator *() const
{
return *s;
}
friend bool operator ==( const c_str_iterator &it1, const c_str_iterator &it2 );
friend bool operator !=( const c_str_iterator &it1, const c_str_iterator &it2 );
protected:
char *s = nullptr;
};
bool operator ==( const c_str_iterator &it1, const c_str_iterator &it2 )
{
return ( it1.s == it2.s ) || ( not it1.s && not *it2.s ) || ( not *it1.s && not it2.s );
}
bool operator !=( const c_str_iterator &it1, const c_str_iterator &it2 )
{
return not ( it1 == it2 );
}
int main()
{
{
char s[] = "Aa Bb Cc Dd";
const char *t = "Cc";
auto it = std::adjacent_find( c_str_iterator( s ), {},
[=]( char c1, char c2 ) { return c1 == t[0] && c2 == t[1]; } );
if ( it != c_str_iterator() ) std::cout << it << std::endl;
}
{
const char *s = "Aa Bb Cc Dd";
const char *t = "Cc";
auto it = std::adjacent_find( const_c_str_iterator( s ), {},
[=]( char c1, char c2 ) { return c1 == t[0] && c2 == t[1]; } );
if ( it != const_c_str_iterator() ) std::cout << it << std::endl;
}
}
Вывод программы на консоль
Cc Dd
Cc Dd