Why the rvalue reference parameter cannot be passed between functions directly? - c++

My code is as follows:
#include <iostream>
using namespace std;
class A{
public:
void sendByRvalue(string&& str){
cout << str << endl;
}
};
class B{
private:
A a;
void send(string&& str){
a.sendByRvalue(str);
}
public:
void run(const string& str){
send("run " + str + "\n");
}
};
int main(void){
string str("hello world");
B b;
b.run(str);
return 0;
}
When I compile the code shown above, I got some compile errors:
It seems that the str in B::send function has been changed to lvalue. Then I change the implement of B::send, like:
class B{
private:
A a;
void send(string&& str){
cout << boolalpha << is_rvalue_reference<decltype(str)>::value << endl;
a.sendByRvalue(std::move(str));
}
public:
void run(const string& str){
send("run " + str + "\n");
}
};
Everything goes well, but the output of this program made me confuse more. The output is as follows:
Why the parameter str is a rvalue reference but I cannot pass it to the function A::sendByRvalue directly without std::move ?

str is a named rvalue reference, which is treated in the language as an lvalue. rvalues are only xvalues or prvalues, and str is neither.
A note from the standard, on the xvalue rules:
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.
struct A {
int m;
};
A&& operator+(A, A);
A&& f();
A a;
A&& ar = static_cast<A&&>(a);
The expressions f(), f().m, static_­cast<A&&>(a), and a + a are xvalues. The expression ar is an lvalue.

I'll make a simpler example to explain
void bar(std::string&& name) {
std::cout << "Bar: " << name << std::endl;
}
void foo(std::string&& name) {
bar(name);
}
int main() {
foo("C++");
}
This is more or less the same as the example you have provided. Inside foo(), name is an lvalue. The temporary string C++, which is an rvalue is passed into name. name is an lvalue. So the above code is basically translated to.
void bar(std::string&& name) {
std::cout << "Bar: " << name << std::endl;
}
int main()
{
std::string foo{ "C++" };
bar(foo);
}
Now it seems obvious where the problem is.
I wrote this simple program to help you understand better
void foo(const std::string& name) {
std::cout << "Passed as lvalue ref: " << name << std::endl;
}
void foo(std::string&& name) {
std::cout << "Passed as rvalue ref: " << name << std::endl;
}
We'll use this function to call
void bar(std::string&& name) {
foo(name);
}
int main() {
bar("C++");
}
Passed as lvalue ref: C++
This proves my point, now what if we use std::move()?
void bar(std::string&& name) {
foo(std::move(name));
}
int main() {
bar("C++");
}
Passed as an rvalue ref: C++
If you want a simple way to check whether an expression is an lvalue or rvalue, you can try the below snippet
template <typename T>
constexpr bool is_lvalue(T&) {
return true;
}
template <typename T>
constexpr bool is_lvalue(T&&) {
return false;
}
source

Related

C++ Is it possible to overload a function so that its argument accept literal and reference respectively?

I'm having a problem with using C++ overloading and was wondering if anybody could help.
I'm trying to overload functions so that its argument accept reference and literal respectively.
For example, I want to overload func1 and func2 to func:
int func1 (int literal);
int func2 (int &reference);
and I want to use func in this situations:
func(3); // call func1
int val = 3;
func(val); // I want func2 to be called, but ambiguous error
Is there any way to overload these functions?
thanks! Any help would be appreciated!
sorry for poor english.
Literals and temporary values can only be passed as const references while named values will prefer a non-const reference if available. You can use this with either & or && to create the 2 overloads.
For why and more details read up on rvalues, lvalues, xvalues, glvalues and prvalues.
The code below shows which function overload will be used for the most common cases, the first 2 being the ones you asked about:
#include <iostream>
void foo1(int &) { std::cout << "int &\n"; }
void foo1(const int &) { std::cout << "const int &\n"; }
void foo2(int &) { std::cout << "int &\n"; }
void foo2(const int &) { std::cout << "const int &\n"; }
void foo2(int &&) { std::cout << "int &&\n"; }
void foo2(const int &&) { std::cout << "const int &&\n"; }
int bla() { return 1; }
int main() {
int x{}, y{};
std::cout << "foo1:\n";
foo1(1);
foo1(x);
foo1(std::move(x));
foo1(bla());
std::cout << "\nfoo2:\n";
foo2(1);
foo2(y);
foo2(std::move(y));
foo2(bla());
}
Output:
foo1:
const int &
int &
const int &
const int &
foo2:
int &&
int &
int &&
int &&

how to create factory function (returning rvalue)

I wrote this piece of code:
class widget_12 {
public:
//reference qualifiers example
void dowork()&
{
std::cout << "*this is lvalue\n";
}; // this version of dowork applies when *this is lvalue
void dowork()&&
{
std::cout << "*this is rvlaue\n";
}; // -||- *this is rvalue
widget_12&& make_widget()
{
//TODO
}
};
I want to test reference qualifiers, therefore I need to create a function that will return the rvalue of widget_12, could you show me how to do it?
I am basically trying to make this call:
make_widget().dowork();
Were you trying something like this?
https://godbolt.org/z/TPEWe3eKv
#include <iostream>
class widget_12 {
public:
//reference qualifiers example
void dowork() &
{
std::cout << "*this is lvalue\n";
}; // this version of dowork applies when *this is lvalue
void doword() &&
{
std::cout << "*this is rvlaue\n";
}; // -||- *this is rvalue
static widget_12 make_widget()
{
return widget_12();
}
};
int main()
{
widget_12 w;
w.dowork();
//w.doword(); // error
widget_12::make_widget().doword();
//widget_12::make_widget().dowork(); // error
return 0;
}

Calling method on temporary objects

I have a class in which I overloaded method. Depending on lifetime of the object given method will be called.
How can I call fun implementation for temporary objects? I thought that std::move() casts its argument to an rvalue. Could you tell me why the code below does not work as intended?
template <typename T>
void fun(T&& arg) {
arg.callamethod();
}
class TestCall {
private:
public:
void callamethod() && {
std::cout << "R VALUE REF" << std::endl;
}
void callamethod() const & {
std::cout << "CONST L VALUE REF" << std::endl;
}
void callamethod() & {
std::cout << "L VALUE REF" << std::endl;
}
};
int main() {
TestCall arg = TestCall();
const TestCall arg2 = TestCall();
fun(arg);
fun(arg2);
fun(std::move(arg)); // calls callamethod() &
fun(std::move(arg2)); // calls callamethod() const &
}
Change your function fun to the following code and you will see that rvalue qualifier on your method callamethod works as expected.
template <typename T>
void fun(T&& arg) {
std::forward<T>(arg).callamethod();
}
Note that the last call:
fun(std::move(arg2));
resolves to the const lvalue option of callamethod as you do not have a const rvalue qualifier option, if you add one it will go to it.

Does this const reference have its life preserved?

I have found this answer to the question "Does a const reference prolong the life of a temporary?", which states:
Only local const references prolong the lifespan.
I'm afraid my standardese is not up to scratch to know whether foo, below, is a local const reference or not.
Does my const std::string& foo below prolong the lifetime of the temporary std::string function argument created in the call to get_or, or do I have a dangling reference?
#include <iostream>
#include <boost/optional.hpp>
struct Foo
{
const std::string& get_or(const std::string& def)
{
return str ? str.get() : def;
}
boost::optional<std::string> str;
};
int main()
{
Foo f;
const std::string& foo = f.get_or("hello world");
std::cout << foo << '\n';
}
const& won't extend lifetimes in that situation. Consider the example here that constructs a temporary and then attempts to print it: it's using the same constructs as your code, but I've altered it to make object construction and destruction more explicit to the user.
#include <iostream>
struct reporting {
reporting() { std::cout << "Constructed" << std::endl;}
~reporting() { std::cout << "Destructed" << std::endl;}
reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;}
reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;}
reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;}
reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;}
void print() const {std::cout << "Printing." << std::endl;}
};
const reporting& get_or(const reporting& def)
{
return def;
}
int main()
{
const reporting& foo = get_or(reporting{});
foo.print();
return 0;
}
Output:
Constructed
Destructed
printing.
Note how the object is destroyed before printing. is displayed.
You might be wondering why the code still completes with no visible errors: it's the result of Undefined Behavior. The object in question doesn't exist, but because it doesn't depend on state to invoke its method, the program happens to not crash. Other, more complicated examples should carry no guarantee that this will work without crashing or causing other, unexpected behavior.
Incidentally, things are a little different if the temporary is bound directly to the const&:
#include <iostream>
struct reporting {
reporting() { std::cout << "Constructed" << std::endl;}
~reporting() { std::cout << "Destructed" << std::endl;}
reporting(reporting const&) { std::cout << "Copy-Constructed" << std::endl;}
reporting(reporting &&) { std::cout << "Move-Constructed" << std::endl;}
reporting & operator=(reporting const&) { std::cout << "Copy-Assigned" << std::endl; return *this;}
reporting & operator=(reporting &&) { std::cout << "Move-Assigned" << std::endl; return *this;}
void print() const {std::cout << "printing." << std::endl;}
};
const reporting& get_or(const reporting& def)
{
return def;
}
int main()
{
const reporting& foo = reporting{};
foo.print();
return 0;
}
Output:
Constructed
printing.
Destructed
See how the object isn't destroyed until after it is used. In this situation, the object survives until the end of scope.
You passed the string through too many references.
Binding the temporary string to the def parameter of get_or extends the lifetime of the string to the end of the full expression containing the function call, but binding def to the return value of get_or and binding the return value of get_or to foo do not extend the lifetime further. The string is dead by the time you try to print it.
The "temporary" in question is the std::string-object created when calling get_or with a parameter of type const char*. The lifetime of this temporary object is limited with the end of function get_or, and the fact that you return a reference to this temporary and assign it afterwards does not prolong the lifetime. See the following code which uses a simple "custom" string class, which couts construction and destruction:
class MyString {
public:
MyString (const char* str) {
m_str = strdup(str);
cout << "constructor MyString - '" << m_str << "'" << endl;
}
~MyString() {
cout << "destructor MyString - '" << m_str << "'" << endl;
free(m_str);
}
char *m_str;
};
struct Foo
{
const MyString& get_or(const MyString& def)
{
cout << "Foo::get_or with '" << def.m_str << "'" << endl;
return def;
}
};
int main()
{
Foo f;
const MyString& foo = f.get_or("hello world");
cout << "usage of foo?" << endl;
}
Output:
constructor MyString - 'hello world'
Foo::get_or with 'hello world'
destructor MyString - 'hello world'
usage of foo?
Note that the destructor is called before you will have the chance to use foo.
The situation is different if you assign a reference to a temporary directly. Again, the lifetime is until the end of the function main, but it will be used in main and not in any function calling main:
const MyString& foo2 = MyString("hello world2");
cout << "usage of foo..." << endl;
Then the output will be:
constructor MyString - 'hello world2'
usage of foo...
destructor MyString - 'hello world2'

Getting the address of an rvalue

class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(MyClass* a) { std::cout << a->a << std::endl; }
int main() {
print(&static_cast<MyClass&&>(MyClass(1337)));
return 0;
}
This doesn't work with GCC 4.6, while it used to work in a previous version.
Now it says: taking address of xvalue (rvalue reference).
Is there any way to securely pass the address of an rvalue to another function?
is: there is anyway to securely pass an rvalue reference (a.k.a. address of temporary) to another function without boringly storing it in a variable just to do that?
Yes, there is, like in the next example :
#include <iostream>
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
void print(MyClass&& a) { std::cout << a.a << std::endl; }
int main() {
print( MyClass(1337) );
}
An rvalue does not necessarily have an address. However, there is a way to get the effect you want, by exploiting the fact that binding an rvalue to a reference forces it to be a temporary (which does have an address):
template<typename T> T *addressOfTemporary(T &&v) { return &v; }
Inside this function, v is an lvalue (despite being declared as T&&), so can have its address taken. You can use this function as follows:
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(MyClass* a) { std::cout << a->a << std::endl; }
int main() {
print(addressOfTemporary(MyClass(1337)));
return 0;
}
Note that the temporary's lifetime ends at the end of the full-expression (the print(...) expression, in this case), so you will need to be careful that the pointer is not used past that point.
If you don't particualrly need to print rvalues only, you can use a standard const reference instead:
class MyClass {
public: MyClass(int a) : a(a) { }
int a;
};
#include <iostream>
void print(const MyClass& a)
{ std::cout << a.a << std::endl; }
int main() {
print(MyClass(1337));
return 0;
}