Итератор с шагом

Рейтинг: 0Ответов: 1Опубликовано: 05.08.2025

Попытался скомпилировать код итератора с шагом из книги C++ Cookbook By Jeff Cogswell, Christopher Diggins, Ryan Stephens, Jonathan Turkanis.

Класс stride_iter должен позволять обращаться к элементам не подряд, а к каждому 2-му, 3-му и т.д.

// код немного изменён мной: добавлен const  и operator-

#include <iterator>
#include <cassert>

template<class Iter_T>
class stride_iter
{
public:
    // public typedefs
    typedef typename std::iterator_traits<Iter_T>::value_type value_type;
    typedef typename std::iterator_traits<Iter_T>::reference reference;
    typedef typename std::iterator_traits<Iter_T>::difference_type
        difference_type;
    typedef typename std::iterator_traits<Iter_T>::pointer pointer;
    typedef std::random_access_iterator_tag iterator_category;
    typedef stride_iter self;

    // constructors
    stride_iter() : m(NULL), step(0) {};
    stride_iter(const self& x) : m(x.m), step(x.step) {}
    stride_iter(Iter_T x, difference_type n) : m(x), step(n) {}

    // operators
    self& operator++() { m += step; return *this; }
    self operator++(int) { self tmp = *this; m += step; return tmp; }
    self& operator+=(difference_type x) { m += x * step; return *this; }
    self& operator--() { m -= step; return *this; }
    self operator--(int) { self tmp = *this; m -= step; return tmp; }
    self& operator-=(difference_type x) { m -= x * step; return *this; }
    reference operator[](difference_type n) const { return m[n * step]; }
    reference operator*() const { return *m; }

    // friend operators
    friend bool operator==(const self& x, const self& y) {
        assert(x.step == y.step);
        return x.m == y.m;
    }
    friend bool operator!=(const self& x, const self& y) {
        assert(x.step == y.step);
        return x.m != y.m;
    }
    friend bool operator<(const self& x, const self& y) {
        assert(x.step == y.step);
        return x.m < y.m;
    }
    friend difference_type operator-(const self& x, difference_type y) {
       assert(x.step == y.step);
       return x -= y * x.step;
    }
    friend difference_type operator-(const self& x, const self& y) {
        assert(x.step == y.step);
        return (x.m - y.m) / x.step;
    }
    friend self operator+(const self& x, difference_type y) {
        assert(x.step == y.step);
        return x += y * x.step;
    }
    friend self operator+(difference_type x, const self& y) {
        assert(x.step == y.step);
        return y += x * x.step;
    }
private:
    Iter_T m;
    difference_type step;
};

Вот как я пытаюсь использовать этот класс (в настройках проекта C++ 20, указывать шаблонный параметр не надо. Если указать, это не поможет):

std::vector<double> v( 100 ); // отсортируем каждый 10й элемент
stride_iter b{ v.begin(),10};
stride_iter e{ v.end(),10};
std::sort(b, e);

Этот код, однако, не компилируется.

double test[100]; // отсортируем каждый 10й элемент
stride_iter b{ test,10 };
stride_iter e{ test+100,10 };
std::sort(b, e);

Тут UB, но это не важно, т.к. этот код тоже не компилируется. MSVC выдаёт ошибку:

test.cpp
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8289,14): error C2672: "std::_Med3_unchecked": не найдена соответствующая перегруженная функция
(компиляция исходного файла "/test.cpp")
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8265,19):
    может быть "void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)"
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8289,14):
        "void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)": в шаблон параметр "_RanIt" неоднозначен
            C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8289,14):
            может быть "_RanIt"
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>
        ]
            C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8289,14):
            или       "__int64"
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8289,14):
        'void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)': не удалось вывести аргумент шаблон для '_RanIt' из '_RanIt'
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>
        ]
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8289,14):
    контекст создания экземпляра шаблона (сначала самый старый)
        C:\myprogs\luamodules\luamkl\test.cpp(10,10):
        выполняется компиляция ссылки на экземпляр шаблон функции "void std::sort<stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>>>(const _RanIt,const _RanIt)"
        with
        [
            _Ty=double,
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>
        ]
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8408,10):
        выполняется компиляция ссылки на экземпляр шаблон функции "void std::sort<_RanIt,std::less<void>>(const _RanIt,const _RanIt,_Pr)"
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>,
            _Pr=std::less<void>
        ]
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8403,10):
        выполняется компиляция ссылки на экземпляр шаблон функции "void std::_Sort_unchecked<_RanIt,_Fn>(_RanIt,_RanIt,__int64,_Pr)"
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>,
            _Fn=std::less<void>,
            _Pr=std::less<void>
        ]
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8384,26):
        выполняется компиляция ссылки на экземпляр шаблон функции "std::pair<_RanIt,_RanIt> std::_Partition_by_median_guess_unchecked<_RanIt,_Pr>(_RanIt,_RanIt,_Pr)"
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>,
            _Pr=std::less<void>
        ]
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8301,10):
        выполняется компиляция ссылки на экземпляр шаблон функции "void std::_Guess_median_unchecked<_RanIt,_Pr>(_RanIt,_RanIt,_RanIt,_Pr)"
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>,
            _Pr=std::less<void>
        ]
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8290,14): error C2672: "std::_Med3_unchecked": не найдена соответствующая перегруженная функция
(компиляция исходного файла "/test.cpp")
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8265,19):
    может быть "void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)"
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8290,14):
        "void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)": в шаблон параметр "_RanIt" неоднозначен
            C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8290,14):
            может быть "_RanIt"
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>
        ]
            C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8290,14):
            или       "__int64"
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8290,14):
        'void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)': не удалось вывести аргумент шаблон для '_RanIt' из '_RanIt'
        with
        [
            _RanIt=stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<double>>>>
        ]
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8291,14): error C2672: "std::_Med3_unchecked": не найдена соответствующая перегруженная функция
(компиляция исходного файла "/test.cpp")
    C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8265,19):
    может быть "void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)"
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8291,14):
        "void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)": в шаблон параметр "_RanIt" неоднозначен
            C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8291,14):
            может быть "__int64"
            C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8291,14):
            или       "stride_iter<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>>"
        with
        [
            _Ty=double
        ]
        C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\include\algorithm(8291,14):
        'void std::_Med3_unchecked(_RanIt,_RanIt,_RanIt,_Pr)': не удалось вывести аргумент шаблон для '_RanIt' из '__int64'

А вот код из STL, на котором выдаётся ошибка:

template <class _RanIt, class _Pr>
_CONSTEXPR20 void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) {
    // sort median element to middle
    using _Diff        = _Iter_diff_t<_RanIt>;
    const _Diff _Count = _Last - _First;
    if (40 < _Count) { // Tukey's ninther
        const _Diff _Step     = (_Count + 1) >> 3; // +1 can't overflow because range was made inclusive in caller
        const _Diff _Two_step = _Step << 1; // note: intentionally discards low-order bit
        _STD _Med3_unchecked(_First, _First + _Step, _First + _Two_step, _Pred);
        _STD _Med3_unchecked(_Mid - _Step, _Mid, _Mid + _Step, _Pred); // здесь ошибка
        _STD _Med3_unchecked(_Last - _Two_step, _Last - _Step, _Last, _Pred);
        _STD _Med3_unchecked(_First + _Step, _Mid, _Last - _Step, _Pred);
    } else {
        _STD _Med3_unchecked(_First, _Mid, _Last, _Pred);
    }
}

Что происходит?

Ответы

▲ 1

Как верно указал @user7860670, в коде были ошибки. Если кому-то вдруг будет надо, работающий код без ошибок выглядит так:

#include <iterator>
#include <cassert>

template<class Iter_T>
class stride_iter
{
public:
    // public typedefs
    typedef typename std::iterator_traits<Iter_T>::value_type value_type;
    typedef typename std::iterator_traits<Iter_T>::reference reference;
    typedef typename std::iterator_traits<Iter_T>::difference_type
        difference_type;
    typedef typename std::iterator_traits<Iter_T>::pointer pointer;
    typedef std::random_access_iterator_tag iterator_category;
    typedef stride_iter self;

    // constructors
    stride_iter() : m(NULL), step(0) {};
    stride_iter(const self& x) : m(x.m), step(x.step) {}
    stride_iter(Iter_T x, difference_type n) : m(x), step(n) {}

    // operators
    self& operator++() { m += step; return *this; }
    self operator++(int) { self tmp = *this; m += step; return tmp; }
    self& operator+=(difference_type x) { m += x * step; return *this; }
    self& operator--() { m -= step; return *this; }
    self operator--(int) { self tmp = *this; m -= step; return tmp; }
    self& operator-=(difference_type x) { m -= x * step; return *this; }
    reference operator[](difference_type n) const { return m[n * step]; }
    reference operator*() const { return *m; }

    // friend operators
    friend bool operator==(const self& x, const self& y) {
        assert(x.step == y.step);
        return x.m == y.m;
    }
    friend bool operator!=(const self& x, const self& y) {
        assert(x.step == y.step);
        return x.m != y.m;
    }
    friend bool operator<(const self& x, const self& y) {
        assert(x.step == y.step);
        return x.m < y.m;
    }
    friend self operator-(const self& x, difference_type y) {
        auto z = x;
        return z -= y * x.step;
    }
    friend difference_type operator-(const self& x, const self& y) {
        assert(x.step == y.step);
        return (x.m - y.m) / x.step;
    }
    friend self operator+(const self& x, difference_type y) {
        auto z = x;
        return z += y * x.step;
    }
    friend self operator+(difference_type x, const self& y) {
        return y += x * y.step;
    }
private:
    Iter_T m;
    difference_type step;
};