2

I have a range over a multi field structure.

The fields can only be accessed via operator [].

I want to run a replace over one of these fields.

I can do this using a range based for loop.

Is there a better way using a range::replace() function ? I am using C++20, but I am also curious if that can be done using C++23 if needed.

#include <ranges>
#include <algorithm>
using namespace std;

enum Direction
{
    HORIZONTAL,
    VERTICAL
};

struct Maille
{
    int16_t i, j;

    int16_t& operator[](Direction input_direction)
    {
        switch (input_direction)
        {
        case HORIZONTAL:
            return j;
        case VERTICAL:
            return i;
        }
    }
    int16_t operator[](Direction input_direction) const
    {
        switch (input_direction)
        {
        case HORIZONTAL:
            return j;
        case VERTICAL:
            return i;
        }
    }
};

int main()
{
    
    Maille tab[2]={
        {.i=1,.j=2},
        {.i=2,.j=1}
    };
    
    for (Maille& m : tab)
    {
        if (m[HORIZONTAL]==1) 
            m[HORIZONTAL]=4;
    }
    
    ranges::replace(tab | views::transform([](Maille& m){
        return m[HORIZONTAL];}),1,4);


    return 0;
}

Error message:

main.cpp: In function ‘int main()’:
main.cpp:52:20: error: no match for call to ‘(const std::ranges::__replace_fn) (std::ranges::transform_view, main():: >, int, int)’
   52 |     ranges::replace(tab | views::transform([](Maille& m){
      |     ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |         return m[HORIZONTAL];}),1,4);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/14/algorithm:63,
                 from main.cpp:3:
/usr/include/c++/14/bits/ranges_algo.h:782:7: note: candidate: ‘template  requires (input_iterator<_Iter>) && (sentinel_for<_Sent, _Iter>) && ((indirectly_writable<_Iter, const _Tp2&>) && (indirect_binary_predicate::__type, const _Tp1*>)) constexpr _Iter std::ranges::__replace_fn::operator()(_Iter, _Sent, const _Tp1&, const _Tp2&, _Proj) const’
  782 |       operator()(_Iter __first, _Sent __last,
      |       ^~~~~~~~
/usr/include/c++/14/bits/ranges_algo.h:782:7: note:   candidate expects 4 arguments, 3 provided
/usr/include/c++/14/bits/ranges_algo.h:799:7: note: candidate: ‘template  requires (input_range<_Range>) && ((indirectly_writable)())), const _Tp2&>) && (indirect_binary_predicate)())), _Proj>::__type, const _Tp1*>)) constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__replace_fn::operator()(_Range&&, const _Tp1&, const _Tp2&, _Proj) const’
  799 |       operator()(_Range&& __r,
      |       ^~~~~~~~
/usr/include/c++/14/bits/ranges_algo.h:799:7: note:   template argument deduction/substitution failed:
/usr/include/c++/14/bits/ranges_algo.h:799:7: note: constraints not satisfied
In file included from /usr/include/c++/14/bits/stl_iterator_base_types.h:71,
                 from /usr/include/c++/14/iterator:61,
                 from /usr/include/c++/14/ranges:43,
                 from main.cpp:2:
/usr/include/c++/14/bits/iterator_concepts.h: In substitution of ‘template<class _Range, class _Tp1, class _Tp2, class _Proj>  requires (input_range<_Range>) && ((indirectly_writable<decltype(std::ranges::__access::__begin((declval<_Container&>)())), const _Tp2&>) && (indirect_binary_predicate<std::ranges::equal_to, typename std::__detail::__projected<decltype(std::ranges::__access::__begin((declval<_Container&>)())), _Proj>::__type, const _Tp1*>)) constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__replace_fn::operator()(_Range&&, const _Tp1&, const _Tp2&, _Proj) const [with _Range = std::ranges::transform_view<std::ranges::ref_view<Maille [2]>, main()::<lambda(Maille&)> >; _Tp1 = int; _Tp2 = int; _Proj = std::identity]’:
main.cpp:52:20:   required from here
   52 |     ranges::replace(tab | views::transform([](Maille& m){
      |     ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |         return m[HORIZONTAL];}),1,4);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/iterator_concepts.h:561:13:   required for the satisfaction of ‘indirectly_writable<decltype (std::ranges::__access::__begin(declval<_Container&>())), const _Tp2&>’ [with _Range = std::ranges::transform_view<std::ranges::ref_view<Maille[2]>, main::._anon_117>; _Tp2 = int]
/usr/include/c++/14/bits/iterator_concepts.h:561:35:   in requirements with ‘_Out&& __o’, ‘_Tp&& __t’ [with _Out = std::ranges::transform_view<std::ranges::ref_view<Maille[2]>, main::._anon_117>::_Iterator<false>; _Tp = const int&]
/usr/include/c++/14/bits/iterator_concepts.h:563:14: note: the required expression ‘*__o =(forward<_Tp>)(__t)’ is invalid
  563 |         *__o = std::forward<_Tp>(__t);
      |         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/iterator_concepts.h:564:34: note: the required expression ‘*(forward<_Out>)(__o)=(forward<_Tp>)(__t)’ is invalid
  564 |         *std::forward<_Out>(__o) = std::forward<_Tp>(__t);
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/iterator_concepts.h:566:11: note: the required expression ‘const_cast)())&&>(*__o) =(forward<_Tp>)(__t)’ is invalid
  565 |         const_cast<const iter_reference_t<_Out>&&>(*__o)
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  566 |           = std::forward<_Tp>(__t);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/iterator_concepts.h:568:11: note: the required expression ‘const_cast)())&&>(*(forward<_Out>)(__o))=(forward<_Tp>)(__t)’ is invalid
  567 |         const_cast<const iter_reference_t<_Out>&&>(*std::forward<_Out>(__o))
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  568 |           = std::forward<_Tp>(__t);
      |           ^~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: note: set ‘-fconcepts-diagnostics-depth=’ to at least 2 for more detail
main.cpp: In member function ‘int16_t& Maille::operator[](Direction)’:
main.cpp:25:9: warning: control reaches end of non-void function [-Wreturn-type]
   25 |         }
      |         ^
1
  • By the why transform when you can use projection with ranges? ranges::replace(tab, 1, 4, &Maille::j); I used the member pointer for succinctness. Commented Feb 13 at 18:52

1 Answer 1

5

The reason you have the error is that lambdas return by value by default, so you are trying to assign to prvalues. You can fix this by specifying a return type for your lambda.

[](Maille& m) -> int16_t& { return m[HORIZONTAL];}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.