27

I am trying to understand why someone would write a function that takes a const rvalue reference.

In the code example below what purpose is the const rvalue reference function (returning "3"). And why does overload resolution preference the const Rvalue above the const LValue reference function (returning "2").

#include <string>
#include <vector>
#include <iostream>

std::vector<std::string> createVector() { return std::vector<std::string>(); } 

//takes movable rvalue
void func(std::vector<std::string> &&p) { std::cout << "1"; }

//takes const lvalue
void func(const std::vector<std::string> &p)  { std::cout << "2"; }

//takes const rvalue???
//what is the point of const rvalue? if const I assume it is not movable?
void func(const std::vector<std::string> &&p) { std::cout << "3"; }

int main()
{
    func(createVector());
    return 0;
}
MW_dev
  • 2,146
  • 1
  • 26
  • 40
  • VC++10. but should be the same on gcc. VC++10 has standard compliant move semantics and overload resolution. – MW_dev Jun 10 '11 at 14:16
  • dupe of http://stackoverflow.com/questions/4938875/do-rvalue-references-to-const-have-any-use – Johannes Schaub - litb Jun 10 '11 at 14:43
  • @litb: It's only partly a duplicate, the question about the overload resolution isn't really addressed in the other question. – reko_t Jun 10 '11 at 15:10
  • Possible duplicate of [Do rvalue references to const have any use?](https://stackoverflow.com/questions/4938875/do-rvalue-references-to-const-have-any-use) – Jonathan Mee Dec 06 '17 at 20:35

2 Answers2

30

Lvalues strongly prefer binding to lvalue references, and similarly rvalue references strongly prefer binding to rvalue references. Modifiable expressions weakly prefer binding to a non-const reference.

So when your compiler is doing overload resolution, it checks if there's an overload that takes an rvalue reference, because that's preferred strongly. In this case since the experssion is a modifiable rvalue, so the rvalue reference overload wins.

There is actually use for const rvalue references, they can be used to make sure something does not bind to an rvalue. Remember that an rvalue binds to a const lvalue reference, hence if you did:

template <typename T> void foo(const T& bar) { /* ... */ }

And called the function with:

foo(createVector());

It'd work fine. However sometimes it is desired to ensure that you can only pass lvalues to a function (this is the case for std::ref for one). You can achieve this by adding an overload:

template <typename T> void foo(const T&&) = delete;

Remember, rvalues strongly prefer binding to rvalue references, and modifiable expressions prefer weakly binding to non-const references. Since we have a const rvalue-reference, it basically means that every single rvalue will bind to this, hence if you try to pass a rvalue to foo(), your compiler will give an error. This is the only way to achieve such functionality, and thus is sometimes useful.

reko_t
  • 55,302
  • 10
  • 87
  • 77
  • Thank you for your in depth answer. When you say: "Lvalues strongly prerfer binding to lvalue references" what do you mean? I do not think LValues can be bound to RValues. Did I misunderstand you you? – MW_dev Jun 10 '11 at 14:45
  • 1
    Lvalues can bind to const rvalue references. *Anything* can bind to const lvalue references as well as const rvalue references. – reko_t Jun 10 '11 at 14:47
  • 3
    This doesn't really give a reason as to why const rvalues themselves are useful, only why you might want a const rvalue reference. – Puppy Jun 10 '11 at 15:22
  • 2
    @reko_t: Minor correction to your answer. This doesn't change your conclusion. But lvalues can not bind to a const rvalue reference. Originally they could. But the rules were changed in the Spring of 2009 such that they can not. An apparent exception to this rule is when deducing against a template parameter of the form `T&&` (non-const). This form is special, and will bind to lvalues (otherwise perfect forwarding wouldn't work). That being said, I completely agree with your use case: http://stackoverflow.com/questions/4938875/do-rvalue-references-to-const-have-any-use/4940642#4940642 – Howard Hinnant Jun 11 '11 at 10:56
  • 1
    DeadMG, that's what the OP asked: `I am trying to understand why someone would write a function that takes a const rvalue reference` – reko_t Jun 11 '11 at 11:38
  • @Howard Hinnant: Ah, that's good to know. I'll update the answer. Thanks! – reko_t Jun 11 '11 at 11:42
  • @reko_t, going by your explaination, the constructor in the following example should bind to const rvalue but that's not the case? #include using namespace std; class A { public: A (int const &&i) { cout << "const rvalue constructor"; } A (int &&i) { cout << "non const rvalue constructor"; } }; int const foo (void) { return 3; } int main (void) { A a(foo()); } – sanjivgupta Jun 27 '18 at 15:46
2

Overload resolution prefers const rvalue over const lvalue because, well, it's an rvalue and you're binding it to an rvalue reference, but you have to add const in both cases, so rvalue reference definitely preferred.

Such things are generally pointless- it's best to leave them binding to the const lvalue overloads. const rvalues don't have any real use.

Puppy
  • 144,682
  • 38
  • 256
  • 465