why the type of obj.i and std::forward<int>(obj.i) are different? - c++11

According to Is a member of an rvalue structure an rvalue or lvalue?:
if E1 is lvalue, then E1.E2 is lvalue, and forward cast its argument to an rvalue only if that argument is bound to an rvalue. In function void foo(Obj &&obj) below, obj is lvalue, so obj.i is lvalue, why is std::forward<int>(obj.i) an rvalue?
class Obj
{
public:
int i;
};
void foo(int &i)
{
cout<<"foo(int&)"<<endl;
}
void foo(int &&i)
{
cout<<"foo(int&&)"<<endl;
}
void foo(Obj &&obj)
{
foo(std::forward<int>(obj.i));
foo(obj.i);
}
int main()
{
Obj obj;
foo(std::move(obj));
return 0;
}
output
foo(int&&)
foo(int&)

You're actually forwarding the wrong thing. In this function:
void foo(Obj &&obj)
{
foo(std::forward<int>(obj.i));
foo(obj.i);
}
obj has name, so it's an lvalue. obj.i is an lvalue in both cases, just in the first you're explicitly casting it to an rvalue! When forward gets a reference type, you get out an lvalue. When it gets a non-reference type, you get an rvalue. You're giving it a non-reference type, so the forward here is equivalent to: foo(std::move(obj.i)); Does that make it clearer why you get an rvalue?
The question you linked, however, is about members of rvalues. To get that, you need to turn obj itself into an rvalue:
foo(std::move(obj).i);
Here, since std::move(obj) is an rvalue, std::move(obj).i is an rvalue as well.
Regardless, using forward when taking an argument by not-forwarding-reference is a little weird. Here's a more general example:
template <class O>
void foo(O&& obj) {
foo(std::forward<O>(obj).i);
}
foo(obj); // calls foo(int&)
foo(std::move(obj)); // calls foo(int&&)
In the former case, std::forward<O>(obj) is an lvalue because O is Obj&, which makes std::foward<O>(obj).i an lvalue. In the latter case, they're both rvalues.

function void foo(Obj &&obj) below:
obj is lvalue, so obj.i is lvalue,
Hmm, do you declare obj as rvalue reference in function proto and then insist it's an lvalue?

According to the specifications of std::forward, the return type is simple an rvalue reference applied to the template type. So the return type std::forward<int> is int&& - used in this way it has exactly the same effect as std::move.
The normal recipe for using std::forward is with universal references:
template<typename T>
void f(T&& val)
{
other_func(std::forward<T>(val));
}
This would work correctly for references, as the deduced type for an lvalue reference in this case would also be an lvalue reference. In your case you're hard-coding the type (to int) rather than deducing it - the deduced type if you used the above pattern would in fact be int&, not int.
You will see that if you change foo(std::forward<int>(obj.i)) to foo(std::forward<int&>(obj.i)) you will get what you expect

Related

std::vector<bool>::reference with std::exchange

Is there a technical reason why std::exchange does not work on std::vector::reference or is it a bug in the implementation of GCC and Clang? With MSVC it compiles fine.
I have a setup like this (minimal example)
struct Manager
{
std::vector<bool> lifeTimes;
//Should return the state before trying to kill it
bool kill(std::size_t index)
{
return std::exchange(lifeTimes[index], false);
}
};
std::exchange would make this a really nice one liner but GCC complains about:
error: cannot bind non-const lvalue reference of type ‘std::_Bit_reference&’ to an rvalue of type ‘std::vector::reference’ {aka ‘std::_Bit_reference’}
So it seams it complains about the false since only the second parameter is an rvalue
It is not a bug, MSVC compiles your code because it has an extension which enables binding temporary object (Rvalue) to non-const Lvalue reference.
Below code compiles with MSVC:
void foo(int& i) {}
foo(20); // you are passing Rvalue and it is bound to Lvalue reference
Above code doesn't compile under G++ or CLang, when you add const to make reference to
const Lvalue, it works:
void foo(const int&){}
foo(20); // you can bind Rvalue to const Lvalue reference
A few words about vector. operator[] for vector<T> where T is every type except bool returns T&:
T& vector<T>::operator[](index) // where T is not bool
For bool vector class template has specialization. Values of bool are stored to hold one bit space, because you cannot use address-of operator for one bit, vector<bool>::operator[](index) cannot return reference. vector<bool> has inner proxy class which manipulates bits (call this class as reference).
vector<bool>::reference vector<bool>::operator[](index)
^^^^^^^^^
as you see object of proxy is passed by value.
So when you call
return std::exchange(lifeTimes[index], false);
you are passing temporary objecy (Rvalue) to exchange which takes first argument by reference to non-const Lvalue. This is the cause that G++ discards this code. If you want to compile it you can explicitly create Lvalue object of proxy class and pass it:
bool kill(std::size_t index)
{
std::vector<bool>::reference proxyForBit = lifeTimes[index];
return std::exchange(proxyForBit, false);
}

std::map of non-movable objects [duplicate]

The following code will not compile on gcc 4.8.2.
The problem is that this code will attempt to copy construct an std::pair<int, A> which can't happen due to struct A missing copy and move constructors.
Is gcc failing here or am I missing something?
#include <map>
struct A
{
int bla;
A(int blub):bla(blub){}
A(A&&) = delete;
A(const A&) = delete;
A& operator=(A&&) = delete;
A& operator=(const A&) = delete;
};
int main()
{
std::map<int, A> map;
map.emplace(1, 2); // doesn't work
map.emplace(std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(2)
); // works like a charm
return 0;
}
As far as I can tell, the issue isn't caused by map::emplace, but by pair's constructors:
#include <map>
struct A
{
A(int) {}
A(A&&) = delete;
A(A const&) = delete;
};
int main()
{
std::pair<int, A> x(1, 4); // error
}
This code example doesn't compile, neither with coliru's g++4.8.1 nor with clang++3.5, which are both using libstdc++, as far as I can tell.
The issue is rooted in the fact that although we can construct
A t(4);
that is, std::is_constructible<A, int>::value == true, we cannot implicitly convert an int to an A [conv]/3
An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed,
for some invented temporary variable t.
Note the copy-initialization (the =). This creates a temporary A and initializes t from this temporary, [dcl.init]/17. This initialization from a temporary tries to call the deleted move ctor of A, which makes the conversion ill-formed.
As we cannot convert from an int to an A, the constructor of pair that one would expect to be called is rejected by SFINAE. This behaviour is surprising, N4387 - Improving pair and tuple analyses and tries to improve the situation, by making the constructor explicit instead of rejecting it. N4387 has been voted into C++1z at the Lenexa meeting.
The following describes the C++11 rules.
The constructor I had expected to be called is described in [pairs.pair]/7-9
template<class U, class V> constexpr pair(U&& x, V&& y);
7 Requires: is_constructible<first_type, U&&>::value is true and
is_constructible<second_type, V&&>::value is true.
8 Effects: The
constructor initializes first with std::forward<U>(x) and second with
std::forward<V>(y).
9 Remarks: If U is not implicitly convertible to
first_type or V is not implicitly convertible to second_type this
constructor shall not participate in overload resolution.
Note the difference between is_constructible in the Requires section, and "is not implicitly convertible" in the Remarks section. The requirements are fulfilled to call this constructor, but it may not participate in overload resolution (= has to be rejected via SFINAE).
Therefore, overload resolution needs to select a "worse match", namely one whose second parameter is a A const&. A temporary is created from the int argument and bound to this reference, and the reference is used to initialize the pair data member (.second). The initialization tries to call the deleted copy ctor of A, and the construction of the pair is ill-formed.
libstdc++ has (as an extension) some nonstandard ctors. In the latest doxygen (and in 4.8.2), the constructor of pair that I had expected to be called (being surprised by the rules required by the Standard) is:
template<class _U1, class _U2,
class = typename enable_if<__and_<is_convertible<_U1, _T1>,
is_convertible<_U2, _T2>
>::value
>::type>
constexpr pair(_U1&& __x, _U2&& __y)
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
and the one that is actually called is the non-standard:
// DR 811.
template<class _U1,
class = typename enable_if<is_convertible<_U1, _T1>::value>::type>
constexpr pair(_U1&& __x, const _T2& __y)
: first(std::forward<_U1>(__x)), second(__y) { }
The program is ill-formed according to the Standard, it is not merely rejected by this non-standard ctor.
As a final remark, here's the specification of is_constructible and is_convertible.
is_constructible [meta.rel]/4
Given the following function prototype:
template <class T>
typename add_rvalue_reference<T>::type create();
the predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:
T t(create<Args>()...);
[Note: These tokens are never interpreted as a function declaration. — end note] Access checking is performed as if in a context unrelated to T and any of the Args. Only the validity of the immediate context of the variable initialization is considered.
is_convertible [meta.unary.prop]/6:
Given the following function prototype:
template <class T>
typename add_rvalue_reference<T>::type create();
the predicate condition for a template specialization is_convertible<From, To> shall be satisfied if and
only if the return expression in the following code would be well-formed, including any implicit conversions
to the return type of the function:
To test() {
return create<From>();
}
[Note: This requirement gives well defined results for reference types, void types, array types, and function types. — end note] Access checking is performed as if in a context unrelated to To and From. Only
the validity of the immediate context of the expression of the return-statement (including conversions to
the return type) is considered.
For your type A,
A t(create<int>());
is well-formed; however
A test() {
return create<int>();
}
creates a temporary of type A and tries to move that into the return-value (copy-initialization). That selects the deleted ctor A(A&&) and is therefore ill-formed.

C++ Do I always have to use std::move to invoke the move constructor?

"Theory" question if you will.
In order to execute/make use of the move constructor in a class, do I always have to use std::move(...) to tell the compiler that I wish to 'move' an object rather than copy it?
Are there any cases where the compiler will invoke the move constructor for me without the use of std::move? (My guess would be in function return values?)
According to cppreference.com (http://en.cppreference.com/w/cpp/language/move_constructor):
The move constructor is called whenever an object is initialized from xvalue of the same type, which includes
initialization, T a = std::move(b); or T a(std::move(b));, where b is of type T;
function argument passing: f(std::move(a));, where a is of type T and f is void f(T t);
function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.
In most cases, yes std::move is needed.
The compiler will invoke the move constructor without std::move when:
returning a local variable by value
when constructing an object from an rvalue of the same type
In all other cases, use std::move. E.g.:
struct S {
std::string name;
S(std::string name) : name(std::move(name)) {}
};
and
std::unique_ptr<Base> func() {
auto p = std::make_unique<Derived>();
return std::move(p); // doesn't work without std::move
}
std::move is just a cast.
unique_ptr<int> global;
auto v = unique_ptr<int>(global); // global is a lvalue, therefore the
unique_ptr(unique_ptr<T>&v) constructor that accepts lvalue references is called.
auto v = unique_ptr<int>(std::move(global)); // move returns a &&rvalue reference, therefore the
unique_ptr(unique_ptr<T>&&v) constructor that accepts &&rvalue references is used.
When the criteria for elision of a copy operation are met and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
therefore,
unique_ptr<int> hello()
{
unique_ptr<int> local;
return local;
// local is an lvalue, but since the critera for elision is met,
// the returned object is created using local as if it was an rvalue
}
Also,
unique_ptr<int> hello = std::unique_ptr<int>();
// we have a pure rvalue in the right, therefore no std::move() cast is needed.

C++11 , move constructor requiring to call std::move explicitely

Case 1 :I am writing a simple move constructor:
ReaderValue::ReaderValue(ReaderValue && other)
{
moveAlloc(other);
}
The moveAlloc function prototype in the ReaderValue class is:
void moveAlloc(ReaderValue && other);
I get the error from gcc 4.8:
cannot bind 'ReaderValue' lvalue to 'ReaderValue&&'
So I need to call explicitely this in order to compile:
moveAlloc(std::move(other));
Case 2 : Now ReaderValue has a std::string stringData member
I make another constructor:
ReaderValue(std::string && otherString)
: stringData(otherString)
{
}
This works, I do not need std::move to pass otherString to the stringData constructor
Question : What is the fundamental reason why I need to explicitely call std::move to pass the rvalue to a function in the first case? The error message says other is a lvalue, whereas it does look like a rvalue reference. Why not in the second case?
(Please don't reply about the actual implementation, or why do I need to do this, blah blah... That's only a fundamental language question)
ReaderValue::ReaderValue(ReaderValue && other)
{
//other here is a lvalue(has a name) referring to a rvalue
//move alloc however takes a rvalue
moveAlloc(other);
}
that is why you have to cast your lvalue to a rvalue explicitely
moveAlloc(std::move(other)); //other now is a rvalue
please note that all std::move does is effectively a cast to rvalue.
In the second example with the string:
ReaderValue(std::string && otherString)
: stringData(otherString)
{ }
calls
std::string(const string& other);
effectively copying the string, while:
ReaderValue(std::string && otherString)
: stringData(std::move(otherString))
{ }
calls:
std::string(string&& other);
moving your string
Suggest you to read this http://thbecker.net/articles/rvalue_references/section_05.html
it'll will tell you why.
In a short, c++ regards parameter other in ReaderValue as a lvalue, but the parameter other in moveAlloc is a rvalue. So you have to convert other in ReaderValue to a rvalue when you call moveAlloc.

What is an rvalue reference to function type?

I have recently wrapped my mind around the C++0x's concepts of glvalues, xvalues and prvalues, as well as the rvalue references. However, there's one thing which still eludes me:
What is "an rvalue reference to function type"? It is literally mentioned many times in the drafts. Why was such a concept introduced? What are the uses for it?
I hate to be circular, but an rvalue reference to function type is an rvalue reference to function type. There is such a thing as a function type, e.g. void (). And you can form an rvalue reference to it.
In terms of the classification system introduced by N3055, it is an xvalue.
Its uses are rare and obscure, but it is not useless. Consider for example:
void f() {}
...
auto x = std::ref(f);
x has type:
std::reference_wrapper<void ()>
And if you look at the synopsis for reference_wrapper it includes:
reference_wrapper(T&) noexcept;
reference_wrapper(T&&) = delete; // do not bind to temporary objects
In this example T is the function type void (). And so the second declaration forms an rvalue reference to function type for the purpose of ensuring that reference_wrapper can't be constructed with an rvalue argument. Not even if T is const.
If it were not legal to form an rvalue reference to function, then this protection would result in a compile time error even if we did not pass an rvalue T to the constructor.
In the old c++ standard the following is forbidden:
int foo();
void bar(int& value);
int main()
{
bar(foo());
}
because the return type of foo() is an rvalue and is passed by reference to bar().
This was allowed though with Microsoft extensions enabled in visual c++ since (i think) 2005.
Possible workarounds without c++0x (or msvc) would be declaring
void bar(const int& value);
or using a temp-variable, storing the return-value of foo() and passing the variable (as reference) to bar():
int main()
{
int temp = foo();
bar(temp);
}

Resources