US 90 compains that the following code does not work as desired:
#include <utility> struct Base { Base(Base&&); }; struct Derived : private Base { Derived(Derived&& d) : Base(std::forward<Base>(d)) { } }; // error: forward can not access Derived's private Base
We looked at this in Rapperswil and came to the mistaken conclusion that the proposed resolution (adopting a design such as that in N2835) would suffer the same error.
We were wrong. Jason Merrill corrected me. The key is to force the implicit conversion from Derived to Base outside of forward, as was done in N2835.
N2835 used four overloads to achieve the desired result. The desired result includes passing all 6 tests outlined in N2951. Daniel Krügler showed how this same behavior can be achieved with only two overloads, and Daniel's formulation is proposed herein.
For implementors: The "ill-formed" requirement in p3 can be implemented with a static_assert which tests that T is not an lvalue reference.
Additionally Stephan T. Lavavej noted that the return statement for move is lacking the necessary cast, so that has been corrected as well.
Change [forward]:
template <class T, class U> T&& forward(U&& u);template <class T> T&& forward(typename remove_reference<T>::type& t); template <class T> T&& forward(typename remove_reference<T>::type&& t);2 Returns: static_cast<T&&>(
ut).3 Remarks: If the second form is instantiated with an lvalue reference type, the program is ill-formed.
if the following constraints are not met, this signature shall not participate in overload resolution:
the type formed by remove_reference<U>::type* is implicitly convertible to the type remove_reference<T>::type*; andif T is an lvalue reference type, then U is also an lvalue reference type.4 ...
5 ...
template <class T> typename remove_reference<T>::type&& move(T&& t);6 Returns: static_cast<typename remove_reference<T>::type&&>(t).