1

In 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);

In 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;
}

In binpack.cpp:

#include "MyRect.h"
...
vector<MyRect> selected_neighboors ;
std::sort(selected_neighboors.begin(), selected_neighboors.end()) ;

Using g++10 (C++20) binpack.cpp compiles. No issues.

If I change to:

ranges::sort(selected_neighboors);

It does not compile any more.

/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
Ludovic Aubert
  • 9,534
  • 4
  • 16
  • 28
  • Your message dump is unreadable. Please format as code. – n. m. could be an AI Feb 05 '22 at 09:30
  • 1
    IIRC the range version requires the full set of comparison operators to be defined. Not sure if it uses them though. – HolyBlackCat Feb 05 '22 at 09:32
  • How can I use "auto operator<=>(const MyRect&) const = default;" to generate them, yet define my own for == ? – Ludovic Aubert Feb 05 '22 at 09:41
  • Can you show what's inside of your `<` and `==`. – HolyBlackCat Feb 05 '22 at 09:53
  • I think what matters is < and == are implemented in MyRect.cpp, so another compile unit. While compiling binpack.cpp, it is not visible. < could be default generated, unlike == which only relies on (left, right, top, bottom), but that is not the issue. – Ludovic Aubert Feb 05 '22 at 10:03
  • Default `<` is gonna be inconsistent with a custom `==` (`!(a < b) && !(b < a)` is supposed to be equivalent to `a == b`), so this is a bad idea. If you show us how `<` and `==` are implemented, we might be able to show how to replace them with `<=>`. – HolyBlackCat Feb 05 '22 at 10:16

1 Answers1

5

ranges::sort uses ranges::less to compare MyRect by default, which is defined in [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.

Its operator() requires that T and U must satisfy total_ordered_with:

template<class T, class U>
  concept totally_­ordered_­with =
    totally_­ordered<T> && totally_­ordered<U> && ...

which requires that T must satisfy totally_ordered:

template<class T>
  concept totally_­ordered =
    equality_­comparable<T> && partially-ordered-with<T, T>;

which requires that T must satisfy 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;
    };

which requires that the full set of the relational operators must be well-formed.

Since you did not define a suitable operator>, operator<= and other relational operators for MyRect, the constraints are not satisfied.

You can add operator<=> to MyRect to make it totally_ordered, or use unconstrained std::less for comparison:

std::vector<MyRect> selected_neighboors;
ranges::sort(selected_neighboors, std::less{});
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • I removed < and == (declaration and implementation). Added auto operator<=>(const MyRect&) const = default; Compilation error diseappeared. – Ludovic Aubert Feb 05 '22 at 14:38