|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Dear Experts,
I'm surprised to find that std::max doesn't work (i.e. won't compile) if the arguments are not of exactly the same type, e.g. one is a short and the other is a long: #include <algorithm> int f(short s, long l) { return std::max(s,l); } $ g++ -W -Wall -c /tmp/maxtest.cc /tmp/maxtest.cc: In function ‘int f(short int, long int)’: /tmp/maxtest.cc:5: error: no matching function for call to ‘max(short int&, long int&)’ I can't even compare a long with an integer constant. Presumably this is a consequence of these functions returning references, not values; you can't return a reference to something that could be a short or could be a long, and promoting to the larger size and returning a reference to the temporary would have its own issues. Any thoughts? Would it be possible to write further overloads for min and max functions that match different argument types return values not references? Regards, Phil. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On Oct 18, 9:19 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org>
wrote: > Dear Experts, > > I'm surprised to find that std::max doesn't work (i.e. won't compile) if > the arguments are not of exactly the same type, e.g. one is a short and > the other is a long: > thats because the template is defined to take two arguments of same type > #include <algorithm> > > int f(short s, long l) { > return std::max(s,l); > > } > > $ g++ -W -Wall -c /tmp/maxtest.cc > /tmp/maxtest.cc: In function 'int f(short int, long int)': > /tmp/maxtest.cc:5: error: no matching function for call to 'max(short > int&, long int&)' > > I can't even compare a long with an integer constant. Yes you can, just explicitly provide template arguments: std::max<long>(s,l); Alternatively, do an explicit cast : std::max((long)s,l); -Neelesh |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
Hi Neelesh, thanks for the quick reply.
Neelesh Bodas wrote: > On Oct 18, 9:19 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org> > wrote: >> Dear Experts, >> >> I'm surprised to find that std::max doesn't work (i.e. won't compile) if >> the arguments are not of exactly the same type, e.g. one is a short and >> the other is a long: >> > > thats because the template is defined to take two arguments of same > type Indeed, but I'm surpised that the short isn't promoted to a long as it would be for a non-template function where both arguments have the same type: int f(long x, long y) { return 1; } int g() { short s; long l; return f(s,l); } I'm not saying that anything is wrong - this just wasn't what I had (naively) expected. > Yes you can, just explicitly provide template arguments: > std::max<long>(s,l); Ah, that's interesting. So if I provide an explicit type then it behaves like my non-template function f above. Thanks, Phil. |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On Oct 18, 9:34 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org>
wrote: > Hi Neelesh, thanks for the quick reply. > > Neelesh Bodas wrote: > > On Oct 18, 9:19 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org> > > wrote: > >> Dear Experts, > > >> I'm surprised to find that std::max doesn't work (i.e. won't compile) if > >> the arguments are not of exactly the same type, e.g. one is a short and > >> the other is a long: > > > thats because the template is defined to take two arguments of same > > type > > Indeed, but I'm surpised that the short isn't promoted to a long as it > would be for a non-template function where both arguments have the same > type: > 14.8.1(4) from the standard: "Implicit conversions will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template parameters that participate in template argument deduction" In the current case since both s and l participate in template argument deduction, s won't be promoted to the type of l. > int f(long x, long y) { > return 1; > > } > > int g() { > short s; > long l; > return f(s,l); > > } > > I'm not saying that anything is wrong - this just wasn't what I had > (naively) expected. > > > Yes you can, just explicitly provide template arguments: > > std::max<long>(s,l); > > Ah, that's interesting. So if I provide an explicit type then it > behaves like my non-template function f above. If you provide the explicit type, then s and l are no more used in template argument deduction. Hence s can be safely promoted to the desired type (long in this case). As another example, this will also work: std::max<int>(s,l); . In this case, both s and l will undergo standard conversion to int. This is possible since neither of them participate in template argument deduction. -N |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
In article <JWLRi.11899$WX3.90@newsfe5-win.ntli.net>,
Phil Endecott <spam_from_usenet_0606@chezphil.org> wrote: > Hi Neelesh, thanks for the quick reply. > > Neelesh Bodas wrote: > > On Oct 18, 9:19 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org> > > wrote: > >> Dear Experts, > >> > >> I'm surprised to find that std::max doesn't work (i.e. won't compile) if > >> the arguments are not of exactly the same type, e.g. one is a short and > >> the other is a long: > >> > > > > thats because the template is defined to take two arguments of same > > type > > Indeed, but I'm surpised that the short isn't promoted to a long as it > would be for a non-template function where both arguments have the same > type: > > int f(long x, long y) { > return 1; > } > > int g() { > short s; > long l; > return f(s,l); > } > > I'm not saying that anything is wrong - this just wasn't what I had > (naively) expected. > > > Yes you can, just explicitly provide template arguments: > > std::max<long>(s,l); > > Ah, that's interesting. So if I provide an explicit type then it > behaves like my non-template function f above. If you use it this be forewarned that you should not catch the return value as a const reference (const long&), but catch it as a long instead. If you catch it as a reference: const long& m = std::max<long>(s,l); then you risk having a reference to a destructed temporary (the temporary long created from converting from s). Here is a more robust (and more flexible) min/max which does not have this danger, and is usable without specifying <long>: http://www.open-std.org/jtc1/sc22/wg...007/n2199.html The std committee briefly considered this solution for standardization in C++0X but rejected it. However the reference implementation is there in the paper free for the taking. -Howard |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
* Howard Hinnant:
> In article <JWLRi.11899$WX3.90@newsfe5-win.ntli.net>, > Phil Endecott <spam_from_usenet_0606@chezphil.org> wrote: > >> Hi Neelesh, thanks for the quick reply. >> >> Neelesh Bodas wrote: >>> On Oct 18, 9:19 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org> >>> wrote: >>>> Dear Experts, >>>> >>>> I'm surprised to find that std::max doesn't work (i.e. won't compile) if >>>> the arguments are not of exactly the same type, e.g. one is a short and >>>> the other is a long: >>>> >>> thats because the template is defined to take two arguments of same >>> type >> Indeed, but I'm surpised that the short isn't promoted to a long as it >> would be for a non-template function where both arguments have the same >> type: >> >> int f(long x, long y) { >> return 1; >> } >> >> int g() { >> short s; >> long l; >> return f(s,l); >> } >> >> I'm not saying that anything is wrong - this just wasn't what I had >> (naively) expected. >> >>> Yes you can, just explicitly provide template arguments: >>> std::max<long>(s,l); >> Ah, that's interesting. So if I provide an explicit type then it >> behaves like my non-template function f above. > > If you use it this be forewarned that you should not catch the return > value as a const reference (const long&), but catch it as a long > instead. If you catch it as a reference: > > const long& m = std::max<long>(s,l); > > then you risk having a reference to a destructed temporary (the > temporary long created from converting from s). Possibly you meant something other than what you actually wrote. std::max returns the same type as the argument type. Therefore, in the example above it returns a 'long', not a 'long const&'. Therefore, the reference is not bound to an internal temporary in the call, but to a temporary that the compiler creates for just this purpose. And that temporary's life is extended to the end of the scope of the reference. It's all very safe. Are you by any chance referring to the reference implementation you link to below? I'm too lazy to check... :-) > Here is a more robust (and more flexible) min/max which does not have > this danger, and is usable without specifying <long>: > > http://www.open-std.org/jtc1/sc22/wg...007/n2199.html > > The std committee briefly considered this solution for standardization > in C++0X but rejected it. However the reference implementation is there > in the paper free for the taking. Cheers, - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
* Alf P. Steinbach:
> * Howard Hinnant: >> In article <JWLRi.11899$WX3.90@newsfe5-win.ntli.net>, >> Phil Endecott <spam_from_usenet_0606@chezphil.org> wrote: >> >>> Hi Neelesh, thanks for the quick reply. >>> >>> Neelesh Bodas wrote: >>>> On Oct 18, 9:19 pm, Phil Endecott <spam_from_usenet_0...@chezphil.org> >>>> wrote: >>>>> Dear Experts, >>>>> >>>>> I'm surprised to find that std::max doesn't work (i.e. won't >>>>> compile) if >>>>> the arguments are not of exactly the same type, e.g. one is a short >>>>> and >>>>> the other is a long: >>>>> >>>> thats because the template is defined to take two arguments of same >>>> type >>> Indeed, but I'm surpised that the short isn't promoted to a long as >>> it would be for a non-template function where both arguments have the >>> same type: >>> >>> int f(long x, long y) { >>> return 1; >>> } >>> >>> int g() { >>> short s; >>> long l; >>> return f(s,l); >>> } >>> >>> I'm not saying that anything is wrong - this just wasn't what I had >>> (naively) expected. >>> >>>> Yes you can, just explicitly provide template arguments: >>>> std::max<long>(s,l); >>> Ah, that's interesting. So if I provide an explicit type then it >>> behaves like my non-template function f above. >> >> If you use it this be forewarned that you should not catch the return >> value as a const reference (const long&), but catch it as a long >> instead. If you catch it as a reference: >> >> const long& m = std::max<long>(s,l); >> >> then you risk having a reference to a destructed temporary (the >> temporary long created from converting from s). > > Possibly you meant something other than what you actually wrote. > > std::max returns the same type as the argument type. Dang, yes it does, but it adds "const&". Sorry. I was unable to believe something like that could have made it into the standard. -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
In article <13hfij37t1bbb2a@corp.supernews.com>,
"Alf P. Steinbach" <alfps@start.no> wrote: > Dang, yes it does, but it adds "const&". > > Sorry. > > I was unable to believe something like that could have made it into the > standard. <chuckle> Not only did we, but we confirmed that we wanted to keep it that way for C++0X! ;-) But I forgot to mention in my previous post that the reference implementation in N2199 uses rvalue-ref. I keep forgetting not everyone has that yet. :-) If you want to play with it I recommend gcc 4.3 or conceptgcc: http://www.generic-programming.org/software/ConceptGCC/ And fwiw, returning a reference isn't always a bad idea, especially a non-const one. Being able to write: int i = 4; int j = 2; max(i, j) = 3; can be very handy. It is only dangerous to return a reference (const or not) if one of the arguments is an rvalue. It is an easy mistake to make in interface design (one I've made myself). -Howard |
|
![]() |
| Outils de la discussion | |
|
|