class outer
{
class inner
{
public:
inner() { }
inner(inner&& rhs);
}
public:
outer() { }
outer(outer&& rhs)
: m_inner(rhs.m_inner) // why is rhs.m_inner an lvalue and not an rvalue?
{ }
private:
inner m_inner;
};
Why is rhs.m_inner an lvalue in this context? If rhs is an rvalue, why is rhs.m_inner not also an rvalue?
The source text rhs refers to two different things here:
The variable rhs, an rvalue-reference to an outer object. This variable has type outer&&.
The expression rhs that evaluates the value of that variable. This expression has type outer and value category lvalue.
The lvalue/rvalue-ness of a reference variable determines to which value categories of expressions the reference can bind, it has no affect on the value category of expressions that evaluate the variable. Evaluating a reference always results in an lvalue.
If rhs was an rvalue, then rhs.m_inner would be an rvalue too. However, rhs is a named variable (doesn't matter that it's an rvalue reference), so it's an lvalue.
With reference to C++ Annotations, to call outer(outer&& rhs), one would use the code:
outer out((outer)outer()/*0*/)/*1*/;
Which at 0 constructs an anonymous object of type outer, and at 1 it constructs an object of type outer with the name out. (The (outer) is there to prevent out form being an outer(outer (*)()))
See the anonymous there? Now consider the definition of outer(outer&& rhs):
outer(outer && rhs) : m_inner(rhs.m_inner) {}
outer(outer &&) has 1 argument of type outer && named rhs.
Now, there is a perceivable difference between the statement 0 in ex. 1 and the first parameter: the former doesn't have a name, the latter does, hence removing the anonimity of the object. Now since the object has a name it is just a lvalue reference (which allows people to use a construct-by-swap idiom). The problem arises, though, when someone needs to use it as a rvalue reference. For that the
template<class T>
typename std::remove_reference<T>::type&& move(T&& t);
function was created. What's it do? It "obtains an rvalue reference to its argument and converts it to an xvalue" (more on all sorts of values here), which is exactly what we need! So, the final code could be:
#include <utility>
class outer {
class inner {
public:
inner() {}
inner(inner && rhs) {}
};
public:
outer() {}
outer(outer && rhs) : m_inner(std::move(rhs.m_inner)) {}
private:
inner m_inner;
};
Note the #include <utility> and std::move() call.
Related
This is part of an assignment, I am stuck at this instruction:
Sort your randomly generated pool of schedules.
Use std::stable_sort,
passing in an object of type schedule_compare as the custom comparison
operator.
UPDATE: I was checking cppreference stable_srot(), see method definition below:
void stable_sort ( RandomAccessIterator first, RandomAccessIterator
last,Compare comp );
, and it seems from what I understood is that you can only pass functions to the last argument (Compare comp) of the stable_sort() i.e:
However, in the instructions, it says that you need to pass an object of type schedule_compare. How is this possible ?
This is my code below:
struct schedule_compare
{
explicit schedule_compare(runtime_matrix const& m)
: matrix_{m} { }
bool operator()(schedule const& obj1, schedule const& obj2) {
if (obj1.score > obj2.score)
return true;
else
return false;
}
private:
runtime_matrix const& matrix_;
};
auto populate_gene_pool(runtime_matrix const& matrix,
size_t const pool_size, random_generator& gen)
{
std::vector<schedule> v_schedule;
v_schedule.reserve(pool_size);
std::uniform_int_distribution<size_t> dis(0, matrix.machines() - 1);
// 4. Sort your randomly generated pool of schedules. Use
// std::stable_sort, passing in an object of type
// schedule_compare as the custom comparison operator.
std::stable_sort(begin(v_schedule), end(v_schedule), ???)
return; v_schedule;
}
For algorithm functions that accepts a "function" (like std::stable_sort) you can pass anything that can be called as a function.
For example a pointer to a global, namespace or static member function. Or you can pass a function-like object instance (i.e. an instance of a class that has a function call operator), also known as a functor object.
This is simply done by creating a temporary object, and passing it to the std::stable_sort (in your case):
std::stable_sort(begin(v_schedule), end(v_schedule), schedule_compare(matrix));
Since the schedule_compare structure have a function call operator (the operator() member function) it can generally be treated like any other function, including being "called".
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.
Consider this:
int func1( int i );
int func2( int i );
Conditional operator can be used like that:
int res = (cond)?func1(4):func2(4);
Or, if both may use the same parameter:
int res = ((cond)?func1:func2)(4);
Now, what about member functions of a class:
class T
{
public:
T( int i ) : i(i) {}
int memfunc1() { return 1*i; }
int memfunc2() { return 2*i; }
private:
int i;
};
I tried this, but it does not work:
T t(4);
int res2 = t.((cond)?memfunc1:memfunc2)();
...tried other syntax too ((t.*((cond)?&(T::memfunc1):&(T::memfunc2)))()) with no success...
Is that doable and then what would be the good syntax? One line code answer are preferable (using a temporary auto variable to store pointer to function would be too easy...;-)
§ 5.3.1 [expr.unary.op]/p4:
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed
in parentheses. [ Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because
there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to
member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. — end note ]
If it still doesn't help, you can uncover the correct syntax below:
(t.*(cond ? &T::memfunc1 : &T::memfunc2))()
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
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.