7

I understand that, given an expression initializing a forwarding/universal reference,lvalues are deduced to be of type T& and rvalues of type T (and not T&&).

Thus,to allow only rvalues, one need to write

template<class T, enable_if<not_<is_lvalue_reference<T> >,OtherConds... > = yes>
void foo(T&& x) {}

and not,

template<class T, enable_if<is_rvalue_reference<T>,OtherConds... > = yes>
void foo(T&& x) {}

My question is , why for forwarding references, rvalues are deduced to be of type T and not T&& ? I guess, if they are deduced as T&& then also same referencing collapsing rule works as T&& && is same as T&&.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
abir
  • 1,797
  • 14
  • 26
  • `enable_if, ...>` would work. :) But as for why it's is deduced as `T` - because that's the way it works with lvalue references? `T&` -> `U` argument -> `U&`. It's the lvalue case that is special, not the rvalue case. – Xeo May 04 '13 at 11:45

1 Answers1

5

Because at the time, deducing rvalue A arguments as A&& instead of A was seen as an unnecessary complication and departure from the normal rules of deduction:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm

We really didn't even know if we could get one exception of the deduction rules (for the lvalue A case), and it never even occurred to us that we would dare ask for two exceptions. To do so, the benefit would have had to have been: It makes what is impossible, possible.

After all, without the single special deduction rule for the lvalue case, perfect forwarding is impossible, as N1385 so aptly demonstrated.

Even with today's hindsight, adding another special deduction rule so that the client can avoid having to negate a template constraint, does not seem like a very high benefit/cost ratio. Especially compared to the benefit/cost ratio we were shooting for in 2002.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • I had gone through those papers, also some other special syntax for perfect forwarding, but never had clear understanding why it was chosen to be `T` rather than `T&&`. Going through n1385, even proposal #7 says about reference collapsing, and says "deduce A1 as a reference type when the argument is an lvalue, and a non-reference type otherwise", but without giving any reason why not rvalue reference type otherwise. I was just curious to know about the history ,as to me deduction of `T&&` instead of `T` looked more symmetric, and looks also works for all cases including `std::forward` – abir May 04 '13 at 17:19
  • 1
    Yes, I agree, I think it would work. But that extra change may well have resulted in "just too much change" for the committee to accept. It could possibly have derailed rvalue-refs in C++11. And there was no motivation to risk it. – Howard Hinnant May 04 '13 at 18:56