0

Basically I want to provide construction from const lvalue versions and rvalue reference versions:

    transform_iterator(const Functor& f, const Iterator& it) :
            functor(f),
            iterator(it)
    {}

    transform_iterator(Functor&& f, Iterator&& it) :
            functor(f),
            iterator(it)
    {}

From what I know, the rvalue reference version is not universal references. Despite that, on this call site:

template <typename InputIt, typename OutputIt>
std::pair<InputIt, OutputIt> sliding_average(InputIt first, InputIt last,
                    const typename std::iterator_traits<InputIt>::difference_type window_length,
                    OutputIt d_first)
{
    using value_type = typename std::iterator_traits<InputIt>::value_type;
    auto divide = [&window_length](const value_type& value)
    {
        return value / window_length;
    };

    auto iterator = shino::transformer(divide, d_first); //transform_iterator<Functor, Iterator>

   shino::sliding_window(first, last, iterator, window_length);
                                       //^^ pass by value

compiler says that rvalue reference version ends up being const lvalue reference version.

For completeness, here is the call site of the sliding_average

sliding_average(v.begin(), v.end(), window_length, output.begin());

where both v and output are vectors of int and doubles, and window_length is std::size_t.

When I remove the const lvalue version, code compiles and works correctly.

Also, this code compiles without problem with both of the constructors:

std::vector<std::string> v{"23", "25", "27"}; //just random numbers
std::vector<int> output(v.size());

auto string_to_int = [](const std::string& x)
{
    return std::stoi(x);
};

auto conversion_iterator = shino::transformer(string_to_int, output.begin());

Question: How to fix it?

Incomputable
  • 2,188
  • 1
  • 20
  • 40

2 Answers2

1

In

auto iterator = shino::transformer(divide, d_first);

You are always going to call the const lvalue reference overload of the function. The reason is that d_first is a named variable. That means it is an lvalue even if it was passed into the function as an rvalue. If you want to make a named variable a rvalue you need to use std::move like

auto iterator = shino::transformer(divide, std::move(d_first));
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

I think that your understanding of lvalues and rvalues is not correct.

You're not invoking transform_iterator::transform_iterator with an rvalue anywhere in the code you've posted.


auto iterator = shino::transformer(divide, d_first);
//                                         ^^^^^^^
//                                         lvalue

To invoke the rvalue reference overload, you need an rvalue! std::move can be used to cast d_first to an rvalue reference - example:

auto iterator = shino::transformer(divide, std::move(d_first));
//                                         ^^^^^^^^^^^^^^^^^^
//                                         rvalue

The same applies to the code you added in your edit:

shino::sliding_window(first, last, iterator, window_length);
//                                 ^^^^^^^^
//                                 lvalue

You probably want:

shino::sliding_window(first, last, std::move(iterator), window_length);
//                                 ^^^^^^^^^^^^^^^^^^^
//                                 rvalue

Relevant questions:

Community
  • 1
  • 1
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416