0

I know that std::move casts an object to rvalue reference:

Return value
static_cast<typename std::remove_reference::type&&>(t)

For a temporary object with prolonged lifetime, I thought it does not make much sence to do std::move on it since it is already dummy &&.
Here is an example:

#include <utility>

int main()
{

  struct dummy {};
  const auto &c = [](dummy &&){};

  dummy &&d = dummy{};
  c(dummy{});
  c(std::move(d));
//  c(d); // does not compile

  [](auto &&){}(d); // compiles
}

https://godbolt.org/z/nqM75KK7M

  • Passing a temporary from dummy{} compiles.
  • Passing a temporary auto &&d to a generic lambda (that accepts auto &&) works, and I expect it to be resolved to dummy&& at compile-time.
  • Passing a temporary auto &&d compiles only with std::move(d). Why? (even clang-tidy says that using std::move on trivially copiable type has no effect.)
<source>: In function 'int main()':
<source>:14:4: error: no match for call to '(const main()::<lambda(main()::dummy&&)>) (main()::dummy&)'
   14 |   c(d); // does not compile
      |   ~^~~
<source>:14:4: note: candidate: 'void (*)(main()::dummy&&)' (conversion)
<source>:14:4: note:   conversion of argument 2 would be ill-formed:
<source>:14:5: error: cannot bind rvalue reference of type 'main()::dummy&&' to lvalue of type 'main()::dummy'
   14 |   c(d); // does not compile
      |     ^
<source>:9:19: note: candidate: 'main()::<lambda(main()::dummy&&)>' (near match)
    9 |   const auto &c = [](dummy &&){};
      |                   ^
<source>:9:19: note:   conversion of argument 1 would be ill-formed:
<source>:14:5: error: cannot bind rvalue reference of type 'main()::dummy&&' to lvalue of type 'main()::dummy'
   14 |   c(d); // does not compile
      |     ^
Compiler returned: 1
Sergey Kolesnik
  • 3,009
  • 1
  • 8
  • 28
  • 1
    `d` in `c(d)` is an lvalue. – Jason Jul 02 '22 at 15:53
  • Please always include a full and complete copy-paste of the errors you get when asking question about build errors. – Some programmer dude Jul 02 '22 at 15:54
  • 2
    As a rule of thumb, anything with a name is an lvalue, and that's what you have here. – Paul Sanders Jul 02 '22 at 16:41
  • In the anonymous lambda case, passing `d` to `auto &&` works because the lambda parameter is a [**forwarding reference**](https://en.cppreference.com/w/cpp/language/reference#Forwarding_references), so it can be either an lvalue reference or an rvalue reference depending on what is actually passed to it. – Remy Lebeau Jul 02 '22 at 18:31
  • @RemyLebeau yeah, I know. I mentioned it in the answer *I expect it to be resolved to dummy&& at compile-time.* What I didn't expect is rvalue reference to be handled as an lvalue. – Sergey Kolesnik Jul 02 '22 at 18:38
  • @SergeyKolesnik but `d` is not an rvalue reference, though. `d` is an **lvalue** whose *type* is an rvalue reference. That is not the same thing as `d` *being* an rvalue. Two different things. – Remy Lebeau Jul 02 '22 at 19:14

0 Answers0