Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > std::max(short,long) doesn't work

Reply
Thread Tools

std::max(short,long) doesn't work

 
 
Phil Endecott
Guest
Posts: n/a
 
      10-18-2007
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.
 
Reply With Quote
 
 
 
 
Neelesh Bodas
Guest
Posts: n/a
 
      10-18-2007
On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
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

 
Reply With Quote
 
 
 
 
Phil Endecott
Guest
Posts: n/a
 
      10-18-2007
Hi Neelesh, thanks for the quick reply.

Neelesh Bodas wrote:
> On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
> 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.
 
Reply With Quote
 
Neelesh Bodas
Guest
Posts: n/a
 
      10-18-2007
On Oct 18, 9:34 pm, Phil Endecott <(E-Mail Removed)>
wrote:
> Hi Neelesh, thanks for the quick reply.
>
> Neelesh Bodas wrote:
> > On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
> > 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

 
Reply With Quote
 
Howard Hinnant
Guest
Posts: n/a
 
      10-18-2007
In article <JWLRi.11899$(E-Mail Removed)>,
Phil Endecott <(E-Mail Removed)> wrote:

> Hi Neelesh, thanks for the quick reply.
>
> Neelesh Bodas wrote:
> > On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
> > 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
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-18-2007
* Howard Hinnant:
> In article <JWLRi.11899$(E-Mail Removed)>,
> Phil Endecott <(E-Mail Removed)> wrote:
>
>> Hi Neelesh, thanks for the quick reply.
>>
>> Neelesh Bodas wrote:
>>> On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
>>> 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?
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      10-18-2007
* Alf P. Steinbach:
> * Howard Hinnant:
>> In article <JWLRi.11899$(E-Mail Removed)>,
>> Phil Endecott <(E-Mail Removed)> wrote:
>>
>>> Hi Neelesh, thanks for the quick reply.
>>>
>>> Neelesh Bodas wrote:
>>>> On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
>>>> 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?
 
Reply With Quote
 
Howard Hinnant
Guest
Posts: n/a
 
      10-18-2007
In article <(E-Mail Removed)>,
"Alf P. Steinbach" <(E-Mail Removed)> 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
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      10-19-2007
On Oct 18, 6:34 pm, Phil Endecott <(E-Mail Removed)>
wrote:
> Hi Neelesh, thanks for the quick reply.


> Neelesh Bodas wrote:
> > On Oct 18, 9:19 pm, Phil Endecott <(E-Mail Removed)>
> > wrote:


> >> 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);
> }


And how should the compiler know that it isn't the opposite
which is wanted. In the above case, you've specified exactly
that there is a single f. With the template, the compiler
could, potentially, instantiate either max(long,long) or
max(short,short). (If you'd written f(short, short) above, it
would also have worked.)

> I'm not saying that anything is wrong - this just wasn't what
> I had (naively) expected.


Templates rarely do.

> > 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 a specific type, the compiler doesn't have to
deduce it. The problem only occurs because the compiler can't
deduce the type when the two arguments have different types.

There have been many different attempts to provide a max/min
which actually work as expected, but it's far from trivial.
Especially as expectations vary. For what you want, you'd
need something like:

template< typename T1, typename T2 >
typename ReturnType< T1, T2 >::type
max( T1 x, T2 y )
{
return x > y ? x : y ;
}

Where ReturnType is something like:

template< typename T1, typename T2 > class ReturnType ;
template< typename T >
class ReturnType< T, T >
{
public:
typedef T type ;
} ;

// Lot's of specializations for mixed types...

Others want max to use only references, so you can write
something like:

max(a,b) = 0 ;

This requires something like:

template< typename T >
T& max( T& a, T& b );

I'm not sure what overload resolution would do if you have both
(although a few simple examples seem to work with g++).

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34

 
Reply With Quote
 
Phil Endecott
Guest
Posts: n/a
 
      10-19-2007
Howard Hinnant wrote:

>>> 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).


And g++ doesn't seem to give a warning in this case, which is a bit
disconcerting as it normally does give some sort of message if you do
something bad with a temporary.


Phil.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
RE;Kontki if you delete kontiki any program you loaded with it in it 'will not work I have tried it with three programs and none work anymore (if you se it just stop download) 1-Twitch Computer Support 5 04-23-2009 02:45 PM
MS work around on text wrapping in a datagrid does not work TB ASP .Net 2 02-22-2006 10:34 PM
Hi I am new to asp i can not get it to work on xp pro sp2 even though the localhost work but asp pages dont so can some one help craig dicker ASP .Net 9 07-07-2005 11:52 AM
Re: Those cute little "WORK-SAFE" / "NOT WORK-SAFE" tags that people put in the Subject headers of their posts... Soapy Digital Photography 1 08-16-2004 12:07 PM
Re: Those cute little "WORK-SAFE" / "NOT WORK-SAFE" tags that people put in the Subject headers of their posts... Soapy Digital Photography 1 08-16-2004 06:24 AM



Advertisments