![]() |
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). |
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 |
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 |
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? |
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 |
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 |
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 |
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 |
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 > |
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 04:25 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.