std::make_shared and std::forward — what's the point? - c++11

I'm trying to understand why std::make_shared is declared/implemented the way it is:
template<class _Tp, class ..._Args>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if
<
!is_array<_Tp>::value,
shared_ptr<_Tp>
>::type
make_shared(_Args&& ...__args)
{
return shared_ptr<_Tp>::make_shared(_VSTD::forward<_Args>(__args)...);
}
What I'm curious about is:
Why does make_shared accept only rvalue-references? Why there's no overload for reference-to-constant (i.e., const _Args &)?
What's the point of _VSTD::forward call?
Good explanation or good hyperlink will both be highly appreciated.

Why does make_shared accept only rvalue-references? Why there's no overload for reference-to-constant (i.e., const _Args &)?
This is a universal reference that binds both to r-values and l-values. For r-values the deduced type is T, for l-values it is T&.
What's the point of _VSTD::forward call?
When a temporary is bound to an r-value reference, that reference (the name) is not r-value any more. You need to be able to restore the original value category of the value and this is what std::forward<> is for: to forward the r-value arguments as r-values and l-value arguments as l-values.
Essentially std::forward applies && to T or T&. When && is applied to
T it becomes T&& - the r-value reference, and
T& becomes T&&&, which is again T&.

Related

What are the requirements for type T in this case?

Given the following function:
template<class T, typename Iterator, typename Function >
T map_reduce(Iterator start, Iterator end, Function f) {
std::Vector<T> vec;
for(; start != end; ++start){
vec.push_back(f(*start));
}
return *start;
}
Can someone explain me why the type T must in this case operator= and Constructor missing parameters and copy c'tor ?
I think that T must copy c'tor because the function return it by-value. But I don't have idea why T must also constructor missing parameters and operator=.
From cppreference:
void push_back( const T& value ); (1)
void push_back( T&& value ); (2)
Type requirements
T must meet the requirements of CopyInsertable in order to use overload (1).
T must meet the requirements of MoveInsertable in order to use overload (2).
Which of these is selected depends on the type of f. Let's assume that f returns an lvalue-reference, which matches (1), because that's the more restrictive one.
That requires, given
std::allocator<T> m;
T* p;
the expression
std::allocator_traits<std::allocator<T>>::construct(m, p, f(*start));
to be well-formed. The note helpfully informs us, in this case, that will be
::new((void*)p) T(f(*start))
You are also (copy?) constructing a T in the return value, when you return *start;. This is likely the source of your "constructor missing parameters" error, as I would expect *start to only relate to T via f.
Note that this is rather likely to be undefined behaviour, as you have just incremented start until it is equal to end. Someone trying to map_reduce everything in a container will pass a non-dereferenceable iterator as end.
As for the missing operator=, who knows? You haven't provided any context to the types involved in the instantiation of this error.

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.

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

The structure of std::forward [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Why use identity in forward definition for C++0x rvalue reference?
I'm really curious- why does std::forward require an explicit template parameter? Couldn't it be simply
template<typename T> T forward(T&& ref) {
return ref;
}
I'd really like all the relevant detail, not simplifications, if possible.
Your implementation makes it impossible to forward an lvalue as an rvalue. With an lvalue A, T deduces as A&, and thus A& is your return type (an lvalue).
See N2951 for a list of use cases forward is meant to be applicable to.
The need to forward an lvalue as an rvalue comes about in the perfect forwarding use case:
template <class T>
void bar(T&& t);
template <class T>
void foo(T&& t)
{
bar(std::forward<T>(t));
}
Inside foo t is always an lvalue. Consider the case foo(A()). T deduces as A, and you want to forward t as an rvalue A, even though t is an lvalue.
forward<A>(t);
casts the lvalue t to A&& (an rvalue).

Resources