Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Template argument as rvalue reference (http://www.velocityreviews.com/forums/t953929-template-argument-as-rvalue-reference.html)

Juha Nieminen 10-26-2012 10:23 AM

Template argument as rvalue reference
 
There's a special rule in the new standard with regard to rvalue references
when used with a template argument. Namely, if you have T&& (where T is
a template argument), it will be collapsed to T& if an lvalue is given
to it.

This means that if you have something like this:

template<typename T> void foo(T&&, T&&);

then two different functions will be instantiated depending on whether
you call it with rvalues or lvalues. In other words foo(1, 2) will
generate one function and foo(a, b) (where a and b are existing variables)
a different one.

What I do not understand is why calling foo(a, 1) or foo(1, b) doesn't
compile. It gives an error (at least with clang).


SG 10-26-2012 10:38 AM

Re: Template argument as rvalue reference
 
Am 26.10.2012 12:23, schrieb Juha Nieminen:> There's a special rule in
the new standard with regard to rvalue references
> when used with a template argument. Namely, if you have T&& (where T
> is a template argument), it will be collapsed to T& if an lvalue is
> given
> to it.


No, reference collapsing is always applicable. It is not restricted to
the case of templates. The only restriction w.r.t. reference collapsing
is that you cannot actually type things like

typedef int && & lvalue_reference;

But you can write

typedef int&& rvalue_reference;
typedef rvalue_reference& lvalue_reference;

The special rule w.r.t. rvalue references is a deduction rule. That is,
if a function receives a parameter of type T&& where T will be deduced,
a special rule kicks in which might render T to be an lvalue reference.
This is done depending on the argument you use to invoke the function
template.

> This means that if you have something like this:
>
> template<typename T> void foo(T&&, T&&);


This is not the way to enable perfect forwarding.

> then two different functions will be instantiated depending on whether
> you call it with rvalues or lvalues. In other words foo(1, 2) will
> generate one function and foo(a, b) (where a and b are existing
> variables) a different one.
>
> What I do not understand is why calling foo(a, 1) or foo(1, b) doesn't
> compile. It gives an error (at least with clang).


Because it's a template argument deduction error.

template<typename T> void foo(T&&, T&&);

int main() {
int a=0, b=0;
foo(1,2); // --> T=int --> T&&=int&&
foo(a,b); // --> T=int& --> T&&=int&
foo(1,b); // deduction error
}

It's a deduction error, because the deduction of T for the first
parameter yields T=int while the deduction of T for the second parameter
yields T=int&&. This is inconsistent and qualifies as deduction failure.
Since no other function or function template called foo is available,
the compiler complains about not being able to call the right foo.

Ok, so, you might think that if the compiler isn't able to figure out
what T is ... how about specifying T? Let's try ...

foo<int>(1,b); // error #1
foo<int&>(1,b); // error #2

#1 is an error because T=int makes the second parameter an rvalue
reference but an rvalue reference of type int is not allowed to be
initialized with an lvalue of int -- for safety reasons.

#2 is an error because T=int& makes the first parameter an lvalue
reference but an lvalue reference of type int is not allowed to be
initialized with an rvalue of int -- for safety reasons, too.

HTH,
SG


SG 10-26-2012 10:43 AM

Re: Template argument as rvalue reference
 
Am 26.10.2012 12:38, schrieb SG:
>
> template<typename T> void foo(T&&, T&&);
>
> int main() {
> int a=0, b=0;
> foo(1,2); // --> T=int --> T&&=int&&
> foo(a,b); // --> T=int& --> T&&=int&
> foo(1,b); // deduction error
> }
>
> It's a deduction error, because the deduction of T for the first
> parameter yields T=int while the deduction of T for the second parameter
> yields T=int&&. This is inconsistent and qualifies as deduction failure.

^^^^^^^
Sorry, this was supposed to be "T=int&".

> HTH,
> SG




Juha Nieminen 10-26-2012 11:20 AM

Re: Template argument as rvalue reference
 
SG <sgesemann@gmail.invalid> wrote:
> No, reference collapsing is always applicable. It is not restricted to
> the case of templates.


I think it is. If you have a non-templated rvalue reference parameter,
you can't give it an lvalue. You'll get a compile error. (I think that
it used to be for a long time that an lvalue could be given to something
taking an rvalue reference, but the changed it much later in the
standardization process.)

The only situation where an rvalue reference is automatically collapsed
to a regular reference is with templates.

>> template<typename T> void foo(T&&, T&&);

>
> This is not the way to enable perfect forwarding.


How is that relevant to my question?

SG 10-26-2012 01:19 PM

Re: Template argument as rvalue reference
 
Am 26.10.2012 13:20, schrieb Juha Nieminen:
> SG <sgesemann@gmail.invalid> wrote:
>> No, reference collapsing is always applicable. It is not restricted to
>> the case of templates.

>
> I think it is.


Then you are wrong. Or perhaps you have a different idea about what
"reference collapsing" means.

> If you have a non-templated rvalue reference parameter,
> you can't give it an lvalue. You'll get a compile error.


What is an "rvalue reference parameter"?

typedef int& foo;

void bar(foo&& x);

void test() {
int a = 23;
bar(a); // actually works
}

Is x of bar an rvalue reference parameter? Well, it looks like one. But
it is not. Due to reference collapsing x is actually an lvalue
reference. This is reference collapsing outside of the context of
templates. Please don't confuse reference collapsing with template
argument deduction.

> The only situation where an rvalue reference is automatically collapsed
> to a regular reference is with templates.


I think you're mixing two different things: reference collapsing and
template argument deduction. The former has nothing to do with templates.

>>> template<typename T> void foo(T&&, T&&);

>>
>> This is not the way to enable perfect forwarding.

>
> How is that relevant to my question?


I dunno. Maybe you're trying to do/understand perfect forwarding. At
least it's the main reason why anybody would use T&& as function
parameter type where T is deduced. In that case, the information that
T&& should only be used for one parameter is useful.

Cheers!
SG


SG 10-26-2012 01:29 PM

Re: Template argument as rvalue reference
 
Am 26.10.2012 15:19, schrieb SG:
> Am 26.10.2012 13:20, schrieb Juha Nieminen:
>> SG <sgesemann@gmail.invalid> wrote:
>>> No, reference collapsing is always applicable. It is not restricted to
>>> the case of templates.

>>
>> I think it is.

>
> Then you are wrong. Or perhaps you have a different idea about what
> "reference collapsing" means.
>
>> If you have a non-templated rvalue reference parameter,
>> you can't give it an lvalue. You'll get a compile error.

>
> What is an "rvalue reference parameter"?
>
> typedef int& foo;
>
> void bar(foo&& x);
>
> void test() {
> int a = 23;
> bar(a); // actually works
> }
>
> Is x of bar an rvalue reference parameter? Well, it looks like one. But
> it is not. Due to reference collapsing x is actually an lvalue
> reference.


Let me stress that this reference collapsing has nothing to do with the
function call or the lvalue 'a' for that matter. Reference collapsing
applies because I wrote "foo&&" where foo is already a reference. The
reference collapsing rules turn foo&& into an lvalue reference as well,
because "lvalue references win", or, to put it differently: & + && = &.

> Cheers!
> SG



ptyxs 10-26-2012 04:59 PM

Re: Template argument as rvalue reference
 
To clarify the matter, may I suggest the various participants to study :

http://thbecker.net/articles/rvalue_...ection_01.html

and Scott Meyers paper in Overload 111 october 2012 :
http://accu.org/index.php/journals/c78/

Everything you discuss is perfectly settled in these two papers.
Ptyxs



ptyxs 10-26-2012 05:00 PM

Re: Template argument as rvalue reference
 
To clarify the matter, may I suggest the various participants to study :

http://thbecker.net/articles/rvalue_...ection_01.html

and Scott Meyers paper in Overload 111 october 2012 :
http://accu.org/index.php/journals/c78/

Everything you discuss is perfectly settled in these two papers.
Ptyxs



ptyxs 10-26-2012 05:00 PM

Re: Template argument as rvalue reference
 
Le 26/10/2012 15:29, SG a écrit :
> Am 26.10.2012 15:19, schrieb SG:
>> Am 26.10.2012 13:20, schrieb Juha Nieminen:
>>> SG <sgesemann@gmail.invalid> wrote:
>>>> No, reference collapsing is always applicable. It is not restricted to
>>>> the case of templates.
>>>
>>> I think it is.

>>
>> Then you are wrong. Or perhaps you have a different idea about what
>> "reference collapsing" means.
>>
>>> If you have a non-templated rvalue reference parameter,
>>> you can't give it an lvalue. You'll get a compile error.

>>
>> What is an "rvalue reference parameter"?
>>
>> typedef int& foo;
>>
>> void bar(foo&& x);
>>
>> void test() {
>> int a = 23;
>> bar(a); // actually works
>> }
>>
>> Is x of bar an rvalue reference parameter? Well, it looks like one. But
>> it is not. Due to reference collapsing x is actually an lvalue
>> reference.

>
> Let me stress that this reference collapsing has nothing to do with the
> function call or the lvalue 'a' for that matter. Reference collapsing
> applies because I wrote "foo&&" where foo is already a reference. The
> reference collapsing rules turn foo&& into an lvalue reference as well,
> because "lvalue references win", or, to put it differently: & + && = &.
>
>> Cheers!
>> SG

>




Juha Nieminen 10-27-2012 07:12 PM

Re: Template argument as rvalue reference
 
SG <sgesemann@gmail.invalid> wrote:
>> If you have a non-templated rvalue reference parameter,
>> you can't give it an lvalue. You'll get a compile error.

>
> What is an "rvalue reference parameter"?


Something like this:

void foo(int&& i);

If you try to give an lvalue to that, it gives an error.

I must admit, I do not know the new standard enough to understand what
exactly is going on here, and why it makes a difference (and why you need
a typedef):

> typedef int& foo;
>
> void bar(foo&& x);



All times are GMT. The time now is 11:51 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.