Я пытаюсь определить итератор, который перебирает ячейки игрового поля-головоломки по заданной начальной ячейке и некоторой ссылке, представляющей своего рода связь между ячейками. Ниже я привел пример кода с теми же методами, но с тривиальной реализацией, которая потенциально должна перебирать ячейки с координатами {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() все еще не компилируется.





Настроенный bool NeighborIterator::operator!=(const NeighborIteratorSentinel&) сделает NeighborIteratorSentinel{} != NeighborIterator{} ll-сформированным, поскольку компилятор не синтезирует соответствующий operator!=, в этом случае это приводит к неудовлетворению sentinel_for ограничений.
В C++20 вам не нужно определять operator!=, просто определите operator==. Компилятор синтезирует для вас все соответствующие операторы равенства (in).
Другими словами, простой обходной путь — удалить оператор != .
Наверное, мне нужно что-то вроде этого stackoverflow.com/questions/40182151/…