This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.

### 1054. `forward` broken

Section: 20.2.4 [forward] Status: Resolved Submitter: Howard Hinnant Opened: 2009-03-13 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [forward].

View all issues with Resolved status.

Discussion:

This is a placeholder issue to track the fact that we (well I) put the standard into an inconsistent state by requesting that we accept N2844 except for the proposed changes to [forward].

There will exist in the post meeting mailing N2835 which in its current state reflects the state of affairs prior to the Summit meeting. I hope to update it in time for the post Summit mailing, but as I write this issue I have not done so yet.

[ Batavia (2009-05): ]

> Move to Open, awaiting the promised paper.

[ 2009-08-02 Howard adds: ]

> My current preferred solution is:

> >     template <class T>
> >     struct __base_type
> >     {
> >        typedef typename remove_cv<typename remove_reference<T>::type>::type type;
> >     };

> >     template <class T, class U,
> >        class = typename enable_if<
> >            !is_lvalue_reference<T>::value ||
> >             is_lvalue_reference<T>::value &&
> >             is_lvalue_reference<U>::value>::type,
> >        class = typename enable_if<
> >             is_same<typename __base_type<T>::type,
> >                     typename __base_type<U>::type>::value>::type>
> >     inline
> >     T&&
> >     forward(U&& t)
> >     {
> >        return static_cast<T&&>(t);
> >     }

> This has been tested by Bill, Jason and myself.

> It allows the following lvalue/rvalue casts:

> 1. Cast an lvalue `t` to an lvalue `T` (identity).
> 2. Cast an lvalue `t` to an rvalue `T`.
> 3. Cast an rvalue `t` to an rvalue `T` (identity).

> It disallows:

> 1. Cast an rvalue `t` to an lvalue `T`.
> 2. Cast one type `t` to another type `T` (such as `int` to `double`).

> "a." is disallowed as it can easily lead to dangling references. "b." is disallowed as this function is meant to only change the lvalue/rvalue characteristic of an expression.

> Jason has expressed concern that "b." is not dangerous and is useful in contexts where you want to "forward" a derived type as a base type. I find this use case neither dangerous, nor compelling. I.e. I could live with or without the "b." constraint. Without it, forward would look like:

> >     template <class T, class U,
> >        class = typename enable_if<
> >            !is_lvalue_reference<T>::value ||
> >             is_lvalue_reference<T>::value &&
> >             is_lvalue_reference<U>::value>::type>
> >     inline
> >     T&&
> >     forward(U&& t)
> >     {
> >        return static_cast<T&&>(t);
> >     }

> Or possibly:

> >     template <class T, class U,
> >        class = typename enable_if<
> >            !is_lvalue_reference<T>::value ||
> >             is_lvalue_reference<T>::value &&
> >             is_lvalue_reference<U>::value>::type,
> >        class = typename enable_if<
> >             is_base_of<typename __base_type<U>::type,
> >                        typename __base_type<T>::type>::value>::type>
> >     inline
> >     T&&
> >     forward(U&& t)
> >     {
> >        return static_cast<T&&>(t);
> >     }

> The "promised paper" is not in the post-Frankfurt mailing only because I'm waiting for the non-concepts draft. But I'm hoping that by adding this information here I can keep people up to date.

[ 2009-08-02 David adds: ]

> `forward` was originally designed to do one thing: perfect forwarding. That is, inside a function template whose actual argument can be a const or non-const lvalue or rvalue, restore the original "rvalue-ness" of the actual argument:

> >     template <class T>
> >     void f(T&& x)
> >     {
> >         // x is an lvalue here.  If the actual argument to f was an
> >         // rvalue, pass static_cast<T&&>(x) to g; otherwise, pass x.
> >         g( forward<T>(x) );
> >     }

> Attempting to engineer `forward` to accomodate uses other than perfect forwarding dilutes its idiomatic meaning. The solution proposed here declares that `forward<T>(x)` means nothing more than `static_cast<T&&>(x)`, with a patchwork of restrictions on what `T` and `x` can be that can't be expressed in simple English.

> I would be happy with either of two approaches, whose code I hope (but can't guarantee) I got right.

> 1. Use a simple definition of `forward` that accomplishes its original purpose without complications to accomodate other uses:

>    >     template <class T, class U>
>    >     T&& forward(U& x)
>    >     {
>    >         return static_cast<T&&>(x);
>    >     }

> 2. Use a definition of `forward` that protects the user from as many potential mistakes as possible, by actively preventing all other uses:

>    >     template <class T, class U>
>    >     boost::enable_if_c<
>    >         // in forward<T>(x), x is a parameter of the caller, thus an lvalue
>    >         is_lvalue_reference<U>::value
>    >         // in caller's deduced T&& argument, T can only be non-ref or lvalue ref
>    >         && !is_rvalue_reference<T>::value
>    >         // Must not cast cv-qualifications or do any type conversions
>    >         && is_same<T&,U&>::value
>    >         , T&&>::type forward(U&& a)
>    >     {
>    >         return static_cast<T&&>(a);
>    >     }

[ 2009-09-27 Howard adds: ]

> A paper, N2951, is available which compares several implementations (including David's) with respect to several use cases (including Jason's) and provides wording for one implementation.

[ 2009-10 Santa Cruz: ]

> NAD Editorial Resolved. Solved by N2951.

Proposed resolution: