What is an rvalue reference to function type? - c++11

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);
}

Related

Use of bind function in boost.asio server example

In boost.asio example of asynchronous UDP server we can find next code:
void start_receive()
{
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
..........
void handle_receive(const boost::system::error_code& error,
std::size_t /*bytes_transferred*/)
According to specification of basic_datagram_socket::async_receive_from function, its prototype is
template<
typename MutableBufferSequence,
typename ReadToken = DEFAULT>
DEDUCED async_receive_from(
const MutableBufferSequence & buffers,
endpoint_type & sender_endpoint,
ReadToken && token = DEFAULT);
when token may be a function with prototype
void handler(
const boost::system::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes received.
);
I do not understand two things (at least)
How bind work here? It accept handle_receive pointer, udp_server object (what for?) and two placeholders. How does it turn to function that is called at the end of asynchronous call and get context varibles?
How does handle_receive function access a recv_buffer_ which is an argument of async_receive_from function but not of handle_receive?
Bind returns a bound function object. There's extensive documentation about how it works and why you'd use it:
https://www.boost.org/doc/libs/1_77_0/libs/bind/doc/html/bind.html
also see https://en.cppreference.com/w/cpp/utility/functional/bind
udp_server object (what for?)
(Non-static) member functions take an implicit this pointer argument to the class instance (object). So a 2-argument non-static member function void X::foo(int,int) consttakes 3 arguments:X const*, int, int`.
How does handle_receive function access a recv_buffer_ which is an argument of async_receive_from function but not of handle_receive?
recv_buffer_ is a data member of the same class (udp_server), so in handle_receive it is implicitly accessing it as this->recv_buffer_. This is very elementary C++, so I recommend maybe reading a good introduction or book if this is new for you.

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.

can std::forward takes std::function<void()> as the class type?

I've always seen std::forward being utilized as below, utilized inside a template function
template<class T>
void foo(T&& arg): bar(std::forward<T>(arg)){}
Suppose I want to do this.
class A
{
private:
std::function<void()> bar;
public:
template<class T>
A(T&& arg):
bar(std::forward<T>(arg))
{}
};
Since bar already has its type defined. I can also directly specify T as std::function<void()> >.
class A
{
private:
std::function<void()> bar;
public:
A(std::function<void()>&& arg):
bar(std::forward<std::function<void()>>(arg))
{}
};
Both would be ok to compile. However, the second realization only support A(const std::function<void()>). While the first realization support A(const std::function<void()>&) and A(std::function<void()>&&) etc.
Forward is a conditional move of its argument. It is almost equivalent to std::move if and only if the type passed to it is a value type or rvalue reference type.
A move is a cast to an rvalue reference.
If you pass a different type to std::forward than its argument type, it will do horrible things. If convertible between, this would often involve creating a temporary within a function then returning a reference to it.
The proper thing to pass to std::forward(x) is X, where the type of x is X&&. Anything else is going to be extremely quirky and advanced use, and will probably cause unexpected behavior...
In your case, the second works fine, but is pointless. As std::forward is a conditional move, and we are passing it a fixed type, we know it is a std::move.
So we should replace std::forward<std::function<void()>>(arg) with std::move(arg), which is both clearer and more conventional. Also, equivalent in this case.
Generally std::forward should only be used in cases where you are using forwarding references.

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

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

Resources