ranges::sort 不编译
ranges::sort does not compile
在MyRect.h中:
struct MyRect
{
MyRect(std::initializer_list<int> i);
MyRect();
int16_t m_left=0, m_right=0, m_top=0, m_bottom=0 ;
int16_t no_sequence=0 ;
int16_t i=-1 ;
bool selected=false ;
} ;
bool operator==(const MyRect& r1, const MyRect& r2) ;
bool operator<(const MyRect& r1, const MyRect& r2);
在MyRect.cpp中:
bool operator==(const MyRect& r1, const MyRect& r2)
{
return r1.m_left==r2.m_left &&
r1.m_right==r2.m_right &&
r1.m_top==r2.m_top &&
r1.m_bottom==r2.m_bottom ;
}
bool operator<(const MyRect& r1, const MyRect& r2)
{
if (r1.m_left != r2.m_left)
return r1.m_left < r2.m_left;
if (r1.m_right != r2.m_right)
return r1.m_right < r2.m_right;
if (r1.m_top != r2.m_top)
return r1.m_top < r2.m_top;
if (r1.m_bottom != r2.m_bottom)
return r1.m_bottom < r2.m_bottom;
//if we got here, r1==r2
return false;
}
在binpack.cpp中:
#include "MyRect.h"
...
vector<MyRect> selected_neighboors ;
std::sort(selected_neighboors.begin(), selected_neighboors.end()) ;
使用 g++10 (C++20) binpack.cpp 编译。没问题。
如果我改成:
ranges::sort(selected_neighboors);
它不再编译。
/home/edouda/linkedboxdraw/binpack.cpp: In function ‘void collapse(std::vector<MyRect>&)’:
/home/edouda/linkedboxdraw/binpack.cpp:617:36: error: no match for call to ‘(const std::ranges::__sort_fn) (std::vector<MyRect>&)’
617 | ranges::sort(selected_neighboors) ;
| ^
In file included from /usr/include/c++/10/algorithm:64,
from /home/edouda/linkedboxdraw/MyRect.h:14,
from /home/edouda/linkedboxdraw/binpack.h:12,
from /home/edouda/linkedboxdraw/binpack.cpp:8:
/usr/include/c++/10/bits/ranges_algo.h:2019:7: note: candidate: ‘template<class _Iter, class _Sent, class _Comp, class _Proj> requires (random_access_iterator<_Iter>) && (sentinel_for<_Sent, _Iter>) && (sortable<_Iter, _Comp, _Proj>) constexpr _Iter std::ranges::__sort_fn::operator()(_Iter, _Sent, _Comp, _Proj) const’
2019 | operator()(_Iter __first, _Sent __last,
| ^~~~~~~~
/usr/include/c++/10/bits/ranges_algo.h:2019:7: note: template argument deduction/substitution failed:
/home/edouda/linkedboxdraw/binpack.cpp:617:36: note: candidate expects 4 arguments, 1 provided
617 | ranges::sort(selected_neighboors) ;
| ^
In file included from /usr/include/c++/10/algorithm:64,
from /home/edouda/linkedboxdraw/MyRect.h:14,
from /home/edouda/linkedboxdraw/binpack.h:12,
from /home/edouda/linkedboxdraw/binpack.cpp:8:
/usr/include/c++/10/bits/ranges_algo.h:2032:7: note: candidate: ‘constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__sort_fn::operator()(_Range&&, _Comp, _Proj) const [with _Range = std::vector<MyRect>&; _Comp = std::ranges::less; _Proj = std::identity; std::ranges::borrowed_iterator_t<_Range> = std::conditional<true, __gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect> >, std::ranges::dangling>::type]’
2032 | operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
| ^~~~~~~~
/usr/include/c++/10/bits/ranges_algo.h:2032:7: note: constraints not satisfied
In file included from /usr/include/c++/10/compare:39,
from /usr/include/c++/10/bits/stl_pair.h:65,
from /usr/include/c++/10/bits/stl_algobase.h:64,
from /usr/include/c++/10/vector:60,
from /home/edouda/linkedboxdraw/MyRect.h:12,
from /home/edouda/linkedboxdraw/binpack.h:12,
from /home/edouda/linkedboxdraw/binpack.cpp:8:
/usr/include/c++/10/concepts: In instantiation of ‘constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__sort_fn::operator()(_Range&&, _Comp, _Proj) const [with _Range = std::vector<MyRect>&; _Comp = std::ranges::less; _Proj = std::identity; std::ranges::borrowed_iterator_t<_Range> = std::conditional<true, __gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect> >, std::ranges::dangling>::type]’:
/home/edouda/linkedboxdraw/binpack.cpp:617:36: required from here
/usr/include/c++/10/concepts:338:13: required for the satisfaction of ‘invocable<_Fn, _Args ...>’ [with _Fn = std::ranges::less&; _Args = {value_type<MyRect>&, value_type<MyRect>&}]
/usr/include/c++/10/concepts:342:13: required for the satisfaction of ‘regular_invocable<_Fn, _Args ...>’ [with _Fn = std::ranges::less&; _Args = {value_type<MyRect>&, value_type<MyRect>&}]
/usr/include/c++/10/concepts:346:13: required for the satisfaction of ‘predicate<_Rel, _Tp, _Tp>’ [with _Rel = std::ranges::less&; _Tp = MyRect&]
/usr/include/c++/10/concepts:351:13: required for the satisfaction of ‘relation<_Rel, _Tp, _Up>’ [with _Rel = std::ranges::less&; _Tp = MyRect&; _Up = MyRect&]
/usr/include/c++/10/concepts:361:13: required for the satisfaction of ‘strict_weak_order<_Fn&, typename std::__detail::__iter_traits_impl<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type> >::type::value_type&, typename std::__detail::__iter_traits_impl<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type> >::type::value_type&>’ [with _Fn = std::ranges::less; _Arg = std::projected<__gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect, std::allocator<MyRect> > >, std::identity>; _Arg = std::projected<__gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect, std::allocator<MyRect> > >, std::identity>]
/usr/include/c++/10/bits/iterator_concepts.h:690:13: required for the satisfaction of ‘indirect_strict_weak_order<_Rel, std::projected<_Iter, _Proj>, std::projected<_Iter, _Proj> >’ [with _Rel = std::ranges::less; _Iter = __gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect, std::allocator<MyRect> > >; _Proj = std::identity]
/usr/include/c++/10/bits/iterator_concepts.h:865:13: required for the satisfaction of ‘sortable<decltype (std::__detail::__ranges_begin(declval<_Container&>())), _Comp, _Proj>’ [with _Container = std::vector<MyRect, std::allocator<MyRect> >&; _Comp = std::ranges::less; _Proj = std::identity]
/usr/include/c++/10/concepts:338:25: note: the expression ‘is_invocable_v<_Fn, _Args ...> [with _Fn = std::ranges::less&; _Args = {value_type<MyRect>&, value_type<MyRect>&}]’ evaluated to ‘false’
338 | concept invocable = is_invocable_v<_Fn, _Args...>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/latuile.dir/build.make:76: CMakeFiles/latuile.dir/binpack.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/latuile.dir/all] Error 2
make: *** [Makefile:95: all] Error 2
ranges::sort
默认使用ranges::less
来比较MyRect
,定义在[range.cmp]:
struct ranges::less {
template<class T, class U>
constexpr bool operator()(T&& t, U&& u) const;
using is_transparent = unspecified;
};
template<class T, class U>
constexpr bool operator()(T&& t, U&& u) const;
Constraints: T
and U
satisfy totally_ordered_with
.
其operator()
要求T
和U
必须满足total_ordered_with
:
template<class T, class U>
concept totally_ordered_with =
totally_ordered<T> && totally_ordered<U> && ...
要求T
必须满足totally_ordered
:
template<class T>
concept totally_ordered =
equality_comparable<T> && partially-ordered-with<T, T>;
要求T
必须满足partially-ordered-with
:
template<class T, class U>
concept partially-ordered-with = // exposition only
requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
{ t < u } -> boolean-testable;
{ t > u } -> boolean-testable;
{ t <= u } -> boolean-testable;
{ t >= u } -> boolean-testable;
{ u < t } -> boolean-testable;
{ u > t } -> boolean-testable;
{ u <= t } -> boolean-testable;
{ u >= t } -> boolean-testable;
};
这要求完整的关系运算符集必须是 well-formed。
由于您没有为MyRect
定义合适的operator>
、operator<=
等关系运算符,不满足约束条件。
你可以在MyRect
上加上operator<=>
使之成为totally_ordered
,或者使用无约束的std::less
进行比较:
std::vector<MyRect> selected_neighboors;
ranges::sort(selected_neighboors, std::less{});
在MyRect.h中:
struct MyRect
{
MyRect(std::initializer_list<int> i);
MyRect();
int16_t m_left=0, m_right=0, m_top=0, m_bottom=0 ;
int16_t no_sequence=0 ;
int16_t i=-1 ;
bool selected=false ;
} ;
bool operator==(const MyRect& r1, const MyRect& r2) ;
bool operator<(const MyRect& r1, const MyRect& r2);
在MyRect.cpp中:
bool operator==(const MyRect& r1, const MyRect& r2)
{
return r1.m_left==r2.m_left &&
r1.m_right==r2.m_right &&
r1.m_top==r2.m_top &&
r1.m_bottom==r2.m_bottom ;
}
bool operator<(const MyRect& r1, const MyRect& r2)
{
if (r1.m_left != r2.m_left)
return r1.m_left < r2.m_left;
if (r1.m_right != r2.m_right)
return r1.m_right < r2.m_right;
if (r1.m_top != r2.m_top)
return r1.m_top < r2.m_top;
if (r1.m_bottom != r2.m_bottom)
return r1.m_bottom < r2.m_bottom;
//if we got here, r1==r2
return false;
}
在binpack.cpp中:
#include "MyRect.h"
...
vector<MyRect> selected_neighboors ;
std::sort(selected_neighboors.begin(), selected_neighboors.end()) ;
使用 g++10 (C++20) binpack.cpp 编译。没问题。
如果我改成:
ranges::sort(selected_neighboors);
它不再编译。
/home/edouda/linkedboxdraw/binpack.cpp: In function ‘void collapse(std::vector<MyRect>&)’:
/home/edouda/linkedboxdraw/binpack.cpp:617:36: error: no match for call to ‘(const std::ranges::__sort_fn) (std::vector<MyRect>&)’
617 | ranges::sort(selected_neighboors) ;
| ^
In file included from /usr/include/c++/10/algorithm:64,
from /home/edouda/linkedboxdraw/MyRect.h:14,
from /home/edouda/linkedboxdraw/binpack.h:12,
from /home/edouda/linkedboxdraw/binpack.cpp:8:
/usr/include/c++/10/bits/ranges_algo.h:2019:7: note: candidate: ‘template<class _Iter, class _Sent, class _Comp, class _Proj> requires (random_access_iterator<_Iter>) && (sentinel_for<_Sent, _Iter>) && (sortable<_Iter, _Comp, _Proj>) constexpr _Iter std::ranges::__sort_fn::operator()(_Iter, _Sent, _Comp, _Proj) const’
2019 | operator()(_Iter __first, _Sent __last,
| ^~~~~~~~
/usr/include/c++/10/bits/ranges_algo.h:2019:7: note: template argument deduction/substitution failed:
/home/edouda/linkedboxdraw/binpack.cpp:617:36: note: candidate expects 4 arguments, 1 provided
617 | ranges::sort(selected_neighboors) ;
| ^
In file included from /usr/include/c++/10/algorithm:64,
from /home/edouda/linkedboxdraw/MyRect.h:14,
from /home/edouda/linkedboxdraw/binpack.h:12,
from /home/edouda/linkedboxdraw/binpack.cpp:8:
/usr/include/c++/10/bits/ranges_algo.h:2032:7: note: candidate: ‘constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__sort_fn::operator()(_Range&&, _Comp, _Proj) const [with _Range = std::vector<MyRect>&; _Comp = std::ranges::less; _Proj = std::identity; std::ranges::borrowed_iterator_t<_Range> = std::conditional<true, __gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect> >, std::ranges::dangling>::type]’
2032 | operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
| ^~~~~~~~
/usr/include/c++/10/bits/ranges_algo.h:2032:7: note: constraints not satisfied
In file included from /usr/include/c++/10/compare:39,
from /usr/include/c++/10/bits/stl_pair.h:65,
from /usr/include/c++/10/bits/stl_algobase.h:64,
from /usr/include/c++/10/vector:60,
from /home/edouda/linkedboxdraw/MyRect.h:12,
from /home/edouda/linkedboxdraw/binpack.h:12,
from /home/edouda/linkedboxdraw/binpack.cpp:8:
/usr/include/c++/10/concepts: In instantiation of ‘constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__sort_fn::operator()(_Range&&, _Comp, _Proj) const [with _Range = std::vector<MyRect>&; _Comp = std::ranges::less; _Proj = std::identity; std::ranges::borrowed_iterator_t<_Range> = std::conditional<true, __gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect> >, std::ranges::dangling>::type]’:
/home/edouda/linkedboxdraw/binpack.cpp:617:36: required from here
/usr/include/c++/10/concepts:338:13: required for the satisfaction of ‘invocable<_Fn, _Args ...>’ [with _Fn = std::ranges::less&; _Args = {value_type<MyRect>&, value_type<MyRect>&}]
/usr/include/c++/10/concepts:342:13: required for the satisfaction of ‘regular_invocable<_Fn, _Args ...>’ [with _Fn = std::ranges::less&; _Args = {value_type<MyRect>&, value_type<MyRect>&}]
/usr/include/c++/10/concepts:346:13: required for the satisfaction of ‘predicate<_Rel, _Tp, _Tp>’ [with _Rel = std::ranges::less&; _Tp = MyRect&]
/usr/include/c++/10/concepts:351:13: required for the satisfaction of ‘relation<_Rel, _Tp, _Up>’ [with _Rel = std::ranges::less&; _Tp = MyRect&; _Up = MyRect&]
/usr/include/c++/10/concepts:361:13: required for the satisfaction of ‘strict_weak_order<_Fn&, typename std::__detail::__iter_traits_impl<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type> >::type::value_type&, typename std::__detail::__iter_traits_impl<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<_Arg>::type>::type> >::type::value_type&>’ [with _Fn = std::ranges::less; _Arg = std::projected<__gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect, std::allocator<MyRect> > >, std::identity>; _Arg = std::projected<__gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect, std::allocator<MyRect> > >, std::identity>]
/usr/include/c++/10/bits/iterator_concepts.h:690:13: required for the satisfaction of ‘indirect_strict_weak_order<_Rel, std::projected<_Iter, _Proj>, std::projected<_Iter, _Proj> >’ [with _Rel = std::ranges::less; _Iter = __gnu_cxx::__normal_iterator<MyRect*, std::vector<MyRect, std::allocator<MyRect> > >; _Proj = std::identity]
/usr/include/c++/10/bits/iterator_concepts.h:865:13: required for the satisfaction of ‘sortable<decltype (std::__detail::__ranges_begin(declval<_Container&>())), _Comp, _Proj>’ [with _Container = std::vector<MyRect, std::allocator<MyRect> >&; _Comp = std::ranges::less; _Proj = std::identity]
/usr/include/c++/10/concepts:338:25: note: the expression ‘is_invocable_v<_Fn, _Args ...> [with _Fn = std::ranges::less&; _Args = {value_type<MyRect>&, value_type<MyRect>&}]’ evaluated to ‘false’
338 | concept invocable = is_invocable_v<_Fn, _Args...>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/latuile.dir/build.make:76: CMakeFiles/latuile.dir/binpack.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:78: CMakeFiles/latuile.dir/all] Error 2
make: *** [Makefile:95: all] Error 2
ranges::sort
默认使用ranges::less
来比较MyRect
,定义在[range.cmp]:
struct ranges::less { template<class T, class U> constexpr bool operator()(T&& t, U&& u) const; using is_transparent = unspecified; };
template<class T, class U> constexpr bool operator()(T&& t, U&& u) const;
Constraints:
T
andU
satisfytotally_ordered_with
.
其operator()
要求T
和U
必须满足total_ordered_with
:
template<class T, class U>
concept totally_ordered_with =
totally_ordered<T> && totally_ordered<U> && ...
要求T
必须满足totally_ordered
:
template<class T>
concept totally_ordered =
equality_comparable<T> && partially-ordered-with<T, T>;
要求T
必须满足partially-ordered-with
:
template<class T, class U>
concept partially-ordered-with = // exposition only
requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
{ t < u } -> boolean-testable;
{ t > u } -> boolean-testable;
{ t <= u } -> boolean-testable;
{ t >= u } -> boolean-testable;
{ u < t } -> boolean-testable;
{ u > t } -> boolean-testable;
{ u <= t } -> boolean-testable;
{ u >= t } -> boolean-testable;
};
这要求完整的关系运算符集必须是 well-formed。
由于您没有为MyRect
定义合适的operator>
、operator<=
等关系运算符,不满足约束条件。
你可以在MyRect
上加上operator<=>
使之成为totally_ordered
,或者使用无约束的std::less
进行比较:
std::vector<MyRect> selected_neighboors;
ranges::sort(selected_neighboors, std::less{});