c++ syntax in understanding rvalue references - c++

I was reading a blog about c++11 rvalue references by Thomas Becker, and the following syntax near the bottom of the page really confuses me.
int& foo();
foo() = 42; // ok, foo() is an lvalue
What exactly is foo? A function pointer that returns a int; an object?
If a function object, how can you assign a value to it, and why is foo a lvalue?

int& foo(); declares a function foo that takes no arguments and returns a reference to an int. For example,
#include <iostream>
int a = 0;
int& foo();
int main()
{
std::cout << a << std::endl;
foo() = 42;
std::cout << a << std::endl;
}
int& foo() { return a; }
Output:
0
42

foo is a function with return type int&. The line
int& foo();
simply declares the function, but does not define it.
When foo is called, the result is an lvalue of type int. Therefore you can assign to it: foo() = 42;

Every function has at least one return expression. Let's look at function calling using the following incomplete, simplified description :
Assume your function signature is T f();, with one return expression return e;. For the sake simplicity, lets also assume that e and T have the same type after removing references and const-ness. In this situation, you can go to your function call location and replace the call f() with (T)e, to understand what's going on.
int& f(){....; return e;}
.
.
.
f() = 5;
becomes
(int&)e = 5;
Of course, if converting e to an lvalue reference(int&) was invalid, the compiler will throw an error.

Related

Pointer to rvalue object member variable

This is a very quick question. I have the following code:
struct integer {
int x;
int& ref() {
return x;
}
};
//main...
int* l = &integer{4}.ref();
std::cout << *l;
My question is: Isn't &integer{4}.ref() a rvalue since it is a temporary object? How can I have a pointer to it? And is it undefined behavior?
While integer{4} is an rvalue, you call ref() which returns an int& which is always an lvalue. This allows the code to compile, but you have undefined behavior since you dereference a pointer to an object that no longer exists.
To fix this you can provide a ref-qualifer for ref which only allows it to be called on lvalues. That would look like
struct integer {
int x;
int& ref() & {
return x;
}
};
and will cause a compiler error if you try to use
integer{4}.ref()
since integer{4} is not an lvalue which ref now requires.

Return statement that calls a function that returns void in a function that returns void

When playing with functions return values, the following code, compiles and works in g++. There is a method that returns void, which calls in a return statement another function that returns void. My question is why do g++ allow this kind of behavior?
#include <iostream>
void Foo()
{
std::cout << "Foo" << std::endl;
}
void Boo()
{
return ( Foo() );
}
int main()
{
Boo();
return ( 0 );
}
According to CPP Reference, when calling return expression;:
The expression is optional in functions whose return type is (possibly cv-qualified) void, and disallowed in constructors and in destructors.
Later, they note:
In a function returning void, the return statement with expression can be used, if the expression type is void.
return can have an expression for a void function as long as the expression is also void, which is what you've done. This could be useful in templates, where the return type of the function may be unknown at the time of writing your function.
void is a type that can be used interchangeably with other types in certain circumstances. Your example would make perfect sense if Boo and Foo returned int; why should changing the type be a special exception to otherwise correct semantics?
return (Foo()) is essentially saying "return nothing," which is, in fact, Boo's stated return type. You'll find that
void bar() {
return void();
}
compiles just fine.

Why can I bind a function taking by-value argument to a std::function taking a lvalue reference?

After digging to find the source of a bug, I was surprised to discover that the following seems to be legal C++11 (compiles fine with GCC/clang with Wall). In particular, why can I assign f1, which takes its argument by value to a RefFunction which expects an argument by reference ?
I tried googling for an explanation, but didn't find anything relevant, probably because I don't know exactly what to google for. I'd really appreciate if someone can guide me through why this is legal.
#include <iostream>
using namespace std;
void f1(int val) {
val = 1;
}
void f2(int& val) {
val = 2;
}
using RefFunction = std::function<void(int&)>;
int main()
{
using namespace std::placeholders;
int val = 42;
// I was expecting a compile error here telling me that f1 doesn't
// have the right signature (int instead of int&)
RefFunction f = f1;
f(val);
cout << val << endl; // prints 42
// This makes sense, f2 takes argument by reference
f = f2;
f(val);
cout << val << endl; // prints 2
return EXIT_SUCCESS;
}
Setting aside the standardese for the time being, think in terms of the following:
void f1(int val) {
val = 1;
}
void f2(int& val) {
val = 2;
}
void WrapperFunction(int& val)
{
f1(val); // Should be OK
f2(val); // Should be OK.
}
The compiler should not have any problems with the above code. If you think of WrapperFunction analogous to a std::function, the compiler should not have any problem regardless of whether the std::function is constructed with f1 or f2.
The template argument of std::function enforces the manner in which the std::function may be called; therefore a RefFunction can only be called with an lvalue of type int or something that can be implicitly converted to an lvalue of type int. It will then call the underlying function, f1 or f2. A function that receives a reference to int can always use that reference to call a function that takes int by value; the int referred to will simply be copied.
In general std::function<R(T...)> can store a callable with any signature as long as it's true that the T... parameters of the std::function's function call operator can actually be used to call the underlying callable. The signatures don't need to match exactly.

Is it legal to take the address of a const lvalue reference?

#include <iostream>
int foo()
{
return 0;
}
int main()
{
const int& a = foo();
std::cout << &a << std::endl;
}
In this code, a binds to a rvalue. Is it legal to take its address? (And by legal I mean: in the code ill-formed? Am I causing an undefined behaviour?)
This is fine. In C++11 you can even do this:
int&& a = foo();
a = 123;
You can kind of think about temporaries like this (conceptually and in general):
x = func(); // translated as:
auto __temporary = func();
x = __temporary;
__destruct_value_now_and_not_later(__temporary);
Except if x is the definition of a reference type, the compiler notes that you're purposefully referring to the temporary value and extends its lifetime by removing the early destruction code, making it a normal variable.
Yes. Until the variable a goes out of scope, the temporary it captures is valid. Herb Sutter can explain it better.

Using decltype to cast this to const

I'm attempting to solve a problem in which decltype will greatly simplify things, but I'm running into an issue using decltype on *this and adding a const qualifier. The sample code below demonstrates the problem.
#include <iostream>
struct Foo
{
void bar()
{
static_cast<const decltype(*this)&>(*this).bar();
}
void bar() const
{
std::cout << "bar" << std::endl;
}
};
int main(int argc, char* argv[])
{
Foo f;
f.bar(); // calls non-const method
return 0;
}
The code compiles in MSVC2010, but execution recurses until a stack overflow occurs.
Ideone reports compiler error
prog.cpp: In member function 'void Foo::bar()':
prog.cpp:7:38: error: 'const' qualifiers cannot be applied to 'Foo&'
If I change the line
static_cast<const decltype(*this)&>(*this).bar();
to
static_cast<const Foo&>(*this).bar();
it works as expected.
Am I misusing or misunderstanding decltype?
Since the expression *this is not an id-expression (i.e. it doesn't name an entity, like a variable), then decltype(*this) gives the type of the expression *this. That type is Foo&, so adding a const qualifier and making a reference to that doesn't change anything: either it silently collapse to Foo& (following rules like reference collapsing), or it's an error (a const reference type). I'm not sure which behaviour is correct, and you have in fact found two compilers which behave differently. In any case it doesn't matter because it's not what you want.
You can use std::remove_reference<decltype(*this)>::type const& instead but that looks a bit ugly.
In case you're still confused:
int* p;
// decltype(p) is the type of the variable p (or, the declared type)
// int*
// decltype( (p) ) is the type of the expression p
// int*& because p is an lvalue
// decltype(*p) is the type of the expression *p
// int& because *p is an lvalue