Myrddin Krustowski
Myrddin Krustowski

Reputation: 771

Implicitly generated function overloads for rvalue argument?

I am sorry if this question was asked before or I am missing something trivial, however the following for references is not clear to me. I understand why passing a rvalue instead of lvalue is allowed when the function parameter is not a reference, however I do not understand the reason it is allowed when the function parameter is a const reference (which doesn't make sense to me) but forbidden when passing a usual reference (the logical behavior).

Suppose that I have the following code

struct A
{
    explicit A(std::string s) : name{ s } { };
    A(const A& a) : name{ a.name } {  }
    A& operator=(const A& a) { name = a.name; return *this; }
    A(A&& a) noexcept : name{} { std::swap(name, a.name); }
    A& operator= (A&& a) noexcept { std::swap(name, a.name); return *this; }
    void talk() const{ std::cout << name << " says blablabla.\n"; }
private:
    std::string name;
};

void f(A a) {}
void g(A& a) {}
void h(const A& a) {}

int main()
{
    A a{ "a" };
    f(a);
    f(A{ "temp" });
    g(a);
    g(A{ "temp" }); // Compile error
    h(a);
    h(A{ "temp" });
}

Now, I understand why there implicitly generated overload for A&& for f, however the behavior for A& and const A& is confusing me.

  1. Why does the compiler forbid passing an A&& instead of A& but allows passing an A&& instead of A&?
  2. Is this a bug or a feature?
  3. In case it is a feature, what is the reason for allowing it?

Thanks.

EDIT: The suggested question is not exactly what I asked. My question was, why does it allow a binding of temporary object even when it is const. The linked question asks "why does it forbid when it is not const".

Accepted answer: The answer provided by eerorika in comments to his question makes most sense, which is backwards compability with pre c++11.

Upvotes: 1

Views: 144

Answers (2)

Dragan
Dragan

Reputation: 66

It is a way to pass expensive values to functions. It allows binding to temporaries because sometimes results from functions are also expensive, and you don't want to pollute the code by saving every expensive value as a variable... C++ does it for you and that's how we get a temporary.

It adds consistency:

//  Whichever you pick, the code below shall be fine.
//using Value = int;
using Value = std::string;
//using Value = std::vector<std::string>;

Value get_something();
Value process(const Value & text);
void set_something(const Value & name);

set_something(process(get_something()); 

Remember: Back in the day, there was no move-semantics. And even with it, moving around values every time they are passed to a function doesn't sit right with me.

Upvotes: 2

eerorika
eerorika

Reputation: 238411

I do not understand the reason [passing a rvalue instead of lvalue] is allowed when the function parameter is a const reference

This makes copying from rvalues possible using copy constructor. There may be other reasons too, but this is quite a useful feature.

Is this a bug or a feature?

It is intentionally specified in the language.

Upvotes: 1

Related Questions