Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm experimenting with Perfect Forwarding and I found that std::forward() needs two overloads:

Overload nr. 1:

template <typename T>
inline T&& forward(typename 
std::remove_reference<T>::type& t) noexcept
{
    return static_cast<T&&>(t);
}

Overload nr.2:

template <typename T>
inline T&& forward(typename 
std::remove_reference<T>::type&& t) noexcept
{
    static_assert(!std::is_lvalue_reference<T>::value,
              "Can not forward an rvalue as an lvalue.");
    return static_cast<T&&>(t);
}

Now a typical scenario for Perfect Forwarding is something like

template <typename T>
void wrapper(T&& e)
{
    wrapped(forward<T>(e));
}

Of course you know that when wrapper() is instantiated, T depends on whether the argument passed to it is an lvalue or an rvalue. If it's an lvalue of type U, T is deduced to U&. If it's an rvalue, T is deduced to U.

In any case - in the scope of wrapper() - e is an lvalue, therefore it always uses the first overload of std::forward().

Now my question:

What is a valid scenario in which the 2nd overload is used (and is needed)?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
289 views
Welcome To Ask or Share your Answers For Others

1 Answer

The design rationale for forward is discussed in great detail in N2951.

This document lays out 6 use cases:

A. Should forward an lvalue as an lvalue. All implementations pass this test. But this is not the classic perfect forwarding pattern. The purpose of this test is to show that implementation 2 fails in its stated goal of preventing all use cases except perfect forwarding.

B. Should forward an rvalue as an rvalue. Like use case A, this is an identity transformation and this presents a motivating example where the identity transformation is needed.

C. Should not forward an rvalue as an lvalue. This use case demonstrates a dangerous situation of accidentally creating a dangling reference.

D. Should forward less cv-qualified expressions to more cv-qualified expressions. A motivating use case involving the addition of const during the forward.

E. Should forward expressions of derived type to an accessible, unambiguous base type. A motivating use case involving forwarding a derived type to a base type.

F. Should not forward arbitrary type conversions. This use case demonstrates how arbitrary conversions within a forward lead to dangling reference run time errors.

The second overload enables cases B and C.

The paper goes on to provide examples of each use case, which are too lengthy to be repeated here.

Update

I've just run the "solution" of just the first overload through these 6 use cases, and this exercise shows that the second overload also enables use case F: Should not forward arbitrary type conversions.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...