Date
2009-08-02.00:00:00
Message id
510

Content

[ 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.