Не могу создать std::ranges::subrange с помощью моего итератора

Я пытаюсь определить итератор, который перебирает ячейки игрового поля-головоломки по заданной начальной ячейке и некоторой ссылке, представляющей своего рода связь между ячейками. Ниже я привел пример кода с теми же методами, но с тривиальной реализацией, которая потенциально должна перебирать ячейки с координатами {0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}:

#include <ranges>

struct CellCoord { size_t col; size_t row; };

struct NeighborIteratorSentinel {};

class NeighborIterator
{
public:

    NeighborIterator(size_t link_id) :
        linkId(link_id)
    {}

    using iterator_category = std::forward_iterator_tag;

    using value_type = CellCoord;

    using difference_type = std::ptrdiff_t;

    using pointer = value_type*;

    using reference = value_type&;

    CellCoord operator-> () const { return cur(); }

    CellCoord operator* () const { return cur(); }

    NeighborIterator& operator++ ()
    {
        ++linkId;

        return *this;
    }

    NeighborIterator operator++ (int)
    {
        NeighborIterator tmp = *this;

        ++linkId;

        return tmp;
    }

    NeighborIterator(const NeighborIterator& other) = default;
    NeighborIterator(NeighborIterator&& other) = default;

    NeighborIterator& operator = (const NeighborIterator& other) = default;
    NeighborIterator& operator = (NeighborIterator&& other) = default;

    NeighborIterator& operator = (const NeighborIteratorSentinel&)
    {
        linkId = linkCount;
    }

    NeighborIterator& operator = (NeighborIteratorSentinel&&)
    {
        linkId = linkCount;
    }

    bool operator == (const NeighborIterator& r) const noexcept
    {
        return linkId == r.linkId;
    }

    bool operator != (const NeighborIterator& r)  const noexcept
    {
        return !operator == (r);
    }

    bool operator == (const NeighborIteratorSentinel&) const noexcept
    {
        return linkId == linkCount;
    }

    bool operator != (const NeighborIteratorSentinel& r)  const noexcept
    {
        return !operator == (r);
    }

protected:

    CellCoord cur() const
    {
        return {linkId, linkId};
    }

private:

    size_t linkId;

    static constexpr size_t linkCount = 5;
};

Проблема в том, что я не могу скомпилировать следующий метод:

inline auto MakeNeighborRange()
{
    return std::ranges::subrange<NeighborIterator, NeighborIteratorSentinel>(NeighborIterator(0u), NeighborIteratorSentinel{});
}

потому что ограничение std::sentinel_for не удовлетворено.

Как сделать эту компиляцию? Чего хочет от меня это ограничение?

Выход MSVC:

C:\dev\temp>cl /std:c++20 /EHsc NeighborIterator.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

NeighborIterator.cpp
NeighborIterator.cpp(101): error C7602: 'std::ranges::subrange': the associated constraints are not satisfied
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3735): note: see declaration of 'std::ranges::subrange'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3733): note: the concept 'std::sentinel_for<example::NeighborIteratorSentinel,example::NeighborIterator>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\__msvc_iter_core.hpp(421): note: the concept 'std::_Weakly_equality_comparable_with<example::NeighborIteratorSentinel,example::NeighborIterator>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(193): note: the concept 'std::_Half_equality_comparable<example::NeighborIteratorSentinel,example::NeighborIterator>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(187): note: 'bool example::NeighborIterator::operator ==(const example::NeighborIteratorSentinel &) noexcept const': rewritten candidate function was excluded from overload resolution because a corresponding operator!= declared in the same scope
NeighborIterator.cpp(75): note: could be 'bool example::NeighborIterator::operator ==(const example::NeighborIteratorSentinel &) noexcept const' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(187): note: 'bool example::NeighborIterator::operator ==(const example::NeighborIteratorSentinel &) noexcept const': rewritten candidate function was excluded from overload resolution because a corresponding operator!= declared in the same scope
NeighborIterator.cpp(65): note: or 'bool example::NeighborIterator::operator ==(const example::NeighborIterator &) noexcept const' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(187): note: 'bool example::NeighborIterator::operator ==(const example::NeighborIterator &) noexcept const': cannot convert argument 2 from 'const example::NeighborIteratorSentinel' to 'const example::NeighborIterator &'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(187): note: Reason: cannot convert from 'const example::NeighborIteratorSentinel' to 'const example::NeighborIterator'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(187): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(5047): note: or       'bool std::operator ==(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *const ) noexcept'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(5041): note: or       'bool std::operator ==(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &) noexcept'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(1661): note: or       'bool std::operator ==(const std::basic_string_view<_Elem,_Traits>,const _Identity<std::basic_string_view<_Elem,_Traits>>::type) noexcept'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(1647): note: or       'bool std::operator ==(const std::basic_string_view<_Elem,_Traits>,const std::basic_string_view<_Elem,_Traits>) noexcept'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xmemory(1042): note: or       'bool std::operator ==(const std::allocator<_Ty> &,const std::allocator<_Other> &) noexcept'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\tuple(872): note: or       'bool std::operator ==(const std::tuple<_Types...> &,const std::tuple<_Types...> &)'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\iterator(488): note: or       'bool std::operator ==(const std::istreambuf_iterator<_Elem,_Traits> &,const std::istreambuf_iterator<_Elem,_Traits> &)'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\iterator(306): note: or       'bool std::operator ==(const std::istream_iterator<_Ty,_Elem,_Traits,_Diff> &,const std::istream_iterator<_Ty,_Elem,_Traits,_Diff> &) noexcept'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(4228): note: or       'bool std::operator ==(const std::move_iterator<_Iter> &,const std::move_iterator<_Iter2> &) noexcept(<expr>)'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(1686): note: or       'bool std::operator ==(const std::reverse_iterator<_BidIt> &,const std::reverse_iterator<_BidIt2> &) noexcept(<expr>)'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\utility(490): note: or       'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Uty1,_Uty2> &)'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\utility(490): note: or 'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Uty1,_Uty2> &)' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(1686): note: or 'bool std::operator ==(const std::reverse_iterator<_BidIt> &,const std::reverse_iterator<_BidIt2> &) noexcept(<expr>)' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(4228): note: or 'bool std::operator ==(const std::move_iterator<_Iter> &,const std::move_iterator<_Iter2> &) noexcept(<expr>)' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\iterator(306): note: or 'bool std::operator ==(const std::istream_iterator<_Ty,_Elem,_Traits,_Diff> &,const std::istream_iterator<_Ty,_Elem,_Traits,_Diff> &) noexcept' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\iterator(488): note: or 'bool std::operator ==(const std::istreambuf_iterator<_Elem,_Traits> &,const std::istreambuf_iterator<_Elem,_Traits> &)' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\tuple(872): note: or 'bool std::operator ==(const std::tuple<_Types...> &,const std::tuple<_Types...> &)' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xmemory(1042): note: or 'bool std::operator ==(const std::allocator<_Ty> &,const std::allocator<_Other> &) noexcept' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(1647): note: or 'bool std::operator ==(const std::basic_string_view<_Elem,_Traits>,const std::basic_string_view<_Elem,_Traits>) noexcept' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(1661): note: or 'bool std::operator ==(const std::basic_string_view<_Elem,_Traits>,const _Identity<std::basic_string_view<_Elem,_Traits>>::type) noexcept' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(5041): note: or 'bool std::operator ==(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &) noexcept' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xstring(5047): note: or 'bool std::operator ==(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *const ) noexcept' [synthesized expression 'y == x']
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(187): note: while trying to match the argument list '(const example::NeighborIteratorSentinel, const example::NeighborIterator)'
NeighborIterator.cpp(101): error C2641: cannot deduce template arguments for 'std::ranges::subrange'
NeighborIterator.cpp(101): error C2783: 'std::ranges::subrange<_It,_Se,_Ki> std::ranges::subrange(std::true_type,_Rng &&)': could not deduce template argument for '_It'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3745): note: see declaration of 'std::ranges::subrange'
NeighborIterator.cpp(101): error C2780: 'std::ranges::subrange<_It,_Se,_Ki> std::ranges::subrange(std::ranges::subrange<_It,_Se,_Ki>)': expects 1 arguments - 2 provided
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3735): note: see declaration of 'std::ranges::subrange'

Это также не компилируется:

inline auto MakeNeighborRange()
{
    return std::ranges::subrange<NeighborIterator>(NeighborIterator(0u), NeighborIterator(0u));
}

Выход MSVC:

C:\dev\temp>cl /std:c++20 /EHsc NeighborIterator.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.39.33523 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

NeighborIterator.cpp
NeighborIterator.cpp(103): error C7602: 'std::ranges::subrange': the associated constraints are not satisfied
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3735): note: see declaration of 'std::ranges::subrange'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3733): note: the concept 'std::sentinel_for<example::NeighborIterator,example::NeighborIterator>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\__msvc_iter_core.hpp(419): note: the concept 'std::semiregular<example::NeighborIterator>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(255): note: the concept 'std::default_initializable<example::NeighborIterator>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(98): note: the concept 'std::constructible_from<example::NeighborIterator,>' evaluated to false
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\concepts(95): note: the constraint was not satisfied
NeighborIterator.cpp(103): error C2641: cannot deduce template arguments for 'std::ranges::subrange'
NeighborIterator.cpp(103): error C2783: 'std::ranges::subrange<_It,_Se,_Ki> std::ranges::subrange(std::true_type,_Rng &&)': could not deduce template argument for '_It'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3745): note: see declaration of 'std::ranges::subrange'
NeighborIterator.cpp(103): error C2780: 'std::ranges::subrange<_It,_Se,_Ki> std::ranges::subrange(std::ranges::subrange<_It,_Se,_Ki>)': expects 1 arguments - 2 provided
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\xutility(3735): note: see declaration of 'std::ranges::subrange'

добавление конструктора по умолчанию исправляет это:

NeighborIterator() : NeighborIterator(0) {}

но первая реализация MakeNeighborRange() все еще не компилируется.

Наверное, мне нужно что-то вроде этого stackoverflow.com/questions/40182151/…

Alexey Starinsky 19.06.2024 01:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Настроенный bool NeighborIterator::operator!=(const NeighborIteratorSentinel&) сделает NeighborIteratorSentinel{} != NeighborIterator{} ll-сформированным, поскольку компилятор не синтезирует соответствующий operator!=, в этом случае это приводит к неудовлетворению sentinel_for ограничений.

В C++20 вам не нужно определять operator!=, просто определите operator==. Компилятор синтезирует для вас все соответствующие операторы равенства (in).

Другими словами, простой обходной путь — удалить оператор != .

Другие вопросы по теме