Search code examples
c++c++11rvalue-reference

Overload function for rvalue and lvalue references


Assume I have some templated class

template <typename T>
struct Dummy {
    // ...
};

And I want to overload a function 'foo' such that it accepts a lvalue or rvalue reference of it. I can do this using some IsDummy trait as follows:

template <typename A>
std::enable_if<IsDummy<A>::value, void>
foo(A &&dummy)
{
    // ....
}

IIRC in some C++11 draft it was legal that

template <typename A>
foo(Dummy<A> &&dummy)
{
    // ....
}

would accept both, lvalue- and value- references.

Now my questions:

  • a) Is it correct that it was allowed in some draft?

  • b) Why was this feature/bug removed? I think I read somewhere that it was due to a conflict with "concepts".

However, I can't find appropriate references for this any more. Does somebody have a better memory or bookmarks?


Solution

  • a) Is it correct that it was allowed in some draft?

    Yes, it was allowed in what is known as "rvalue references 1.0" (see N2118).

    b) Why was this feature/bug removed? I think I read somewhere that it was due to a conflict with "concepts".

    It was removed because binding an rvalue reference to an lvalue could lead to a violation of the "Principle of Type-safe Overloading" in the presence of Concepts:

    Every function must be type-safe in isolation, without regard to how it has been overloaded.

    For example, if we define the following overloads:

    template< CopyConstructible T > void f( T const & t ); // #1
    template< MoveConstructible T > void f( T && t );      // #2
    

    Then calling f with a copyable lvalue would select #1. However, if T is a non-copyable type (e.g. std::unique_ptr) then #1 is not a viable overload so the compiler must select #2, possibly stealing resources from an lvalue without warning.

    See "rvalue references 2.0" (N2844) for more details.