Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

template error

0 views
Skip to first unread message

asit

unread,
Jul 29, 2009, 1:15:43 PM7/29/09
to
Why the following code shows terrific error ???

//minmax.h

template <class T>
T max(T a, T b)
{
if(a>b)
return a;
else
return b;
}

template <class T>
T min(T a, T b)
{
if(a>b)
return b;
else
return a;
}

//tminmax.cpp
#include <iostream>
#include "minmax.h"

using namespace std;

int main()
{
int i1=100, i2=200;
double d1=3.14159, d2=9.87654;
char c1='A', c2='z';

cout<<"max(i1, i2) == "<<max(i1, i2)<<endl;
cout<<"max(d1, d2) == "<<max(d1, d2)<<endl;
cout<<"max(c1, c2) == "<<max(c1, c2)<<endl;

cout<<"min(i1, i2) == "<<min(i1, i2)<<endl;
cout<<"min(d1, d2) == "<<min(d1, d2)<<endl;
cout<<"min(c1, c2) == "<<min(c1, c2)<<endl;

return 0;
}

When I compiled it, it gave me the following o/p

C:\cpp>g++ -o tminmax.exe tminmax.cpp
tminmax.cpp: In function `int main()':
tminmax.cpp:12: error: call of overloaded `max(int&, int&)' is
ambiguous
minmax.h:3: note: candidates are: T max(T, T) [with T = int]
F:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/
bits/stl_a
lgobase.h:173: note: const _Tp& std::max(const _Tp&,
const _Tp&)
[with _Tp = int]
tminmax.cpp:13: error: call of overloaded `max(double&, double&)' is
ambiguous
minmax.h:3: note: candidates are: T max(T, T) [with T = double]
F:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/
bits/stl_a
lgobase.h:173: note: const _Tp& std::max(const _Tp&,
const _Tp&)
[with _Tp = double]
tminmax.cpp:14: error: call of overloaded `max(char&, char&)' is
ambiguous
minmax.h:3: note: candidates are: T max(T, T) [with T = char]
F:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/
bits/stl_a
lgobase.h:173: note: const _Tp& std::max(const _Tp&,
const _Tp&)
[with _Tp = char]
tminmax.cpp:16: error: call of overloaded `min(int&, int&)' is
ambiguous
minmax.h:12: note: candidates are: T min(T, T) [with T = int]
F:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/
bits/stl_a
lgobase.h:151: note: const _Tp& std::min(const _Tp&,
const _Tp&)
[with _Tp = std::streamsize]
tminmax.cpp:17: error: call of overloaded `min(double&, double&)' is
ambiguous
minmax.h:12: note: candidates are: T min(T, T) [with T = double]
F:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/
bits/stl_a
lgobase.h:151: note: const _Tp& std::min(const _Tp&,
const _Tp&)
[with _Tp = double]
tminmax.cpp:18: error: call of overloaded `min(char&, char&)' is
ambiguous
minmax.h:12: note: candidates are: T min(T, T) [with T = char]
F:/Dev-Cpp/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/
bits/stl_a
lgobase.h:151: note: const _Tp& std::min(const _Tp&,
const _Tp&)
[with _Tp = char]

SG

unread,
Jul 29, 2009, 1:47:21 PM7/29/09
to
Hello asit,

I shortened your code a bit but it's practically the same:

On 29 Jul., 19:15, asit <lipu...@gmail.com> wrote:
>
> #include <iostream>


>
> template <class T>
> T max(T a, T b)
> {
>         if(a>b) return a;
>         else    return b;
> }
>
> template <class T>
> T min(T a, T b)
> {
>         if(a>b) return b;
>         else    return a;
> }

You should have used the less than operator < here. It's common
practise to use < for ordering. Some types might only support less
than.

> using namespace std;

You're making every name in std:: accessible without qualification.
This may include std::min and std::max you otherwise find in the
<algorithm> header.

> int main()
> {
>         int i1=100, i2=200;
>         double d1=3.14159, d2=9.87654;
>         char c1='A', c2='z';
>
>         cout<<"max(i1, i2) == "<<max(i1, i2)<<endl;
>         cout<<"max(d1, d2) == "<<max(d1, d2)<<endl;
>         cout<<"max(c1, c2) == "<<max(c1, c2)<<endl;
>
>         cout<<"min(i1, i2) == "<<min(i1, i2)<<endl;
>         cout<<"min(d1, d2) == "<<min(d1, d2)<<endl;
>         cout<<"min(c1, c2) == "<<min(c1, c2)<<endl;
>
>         return 0;
> }
>
> When I compiled it, it gave me the following o/p
>
> C:\cpp>g++ -o tminmax.exe tminmax.cpp
> tminmax.cpp: In function `int main()':
> tminmax.cpp:12: error: call of overloaded `max(int&, int&)' is
> ambiguous
> minmax.h:3: note: candidates are: T max(T, T) [with T = int]

> lgobase.h:173: note:             const _Tp& std::max(const _Tp&,
> const _Tp&) [with _Tp = int]

There's your explanation. The compiler doesn't know whether you meant
the template you wrote in the global scope or std::max. Both are
accessible due to the using directive.

The name lookup rules are a bit complicated. Let me try to give a
simple explanation for this situation: A using directive for a
namespace X makes the compiler look into the namespace X as well when
it has to search the global scope.

You can solve this problem in a number of ways. I'm going to mention
three:

(A) Replace the using directive with a couple of using
declarations:

using std::cout;
using std::endl;

(B) Keep the using directive and put your functions and classes
in your own namespace N. When you use an unqualified name X
inside your namespace N, the names in std:: will only be
considered in case your own namespace doesn't contain an X.
If your namespace contains an X it will "hide" other Xs from
the global scope.

(C) Keep the using directive and make sure that you don't
use names that also live in the std:: namespace.


Cheers!
SG

Juha Nieminen

unread,
Jul 29, 2009, 3:04:17 PM7/29/09
to
SG wrote:
> You can solve this problem in a number of ways. I'm going to mention
> three:
>
> (A) Replace the using directive with a couple of using
> declarations:
>
> using std::cout;
> using std::endl;
>
> (B) Keep the using directive and put your functions and classes
> in your own namespace N. When you use an unqualified name X
> inside your namespace N, the names in std:: will only be
> considered in case your own namespace doesn't contain an X.
> If your namespace contains an X it will "hide" other Xs from
> the global scope.
>
> (C) Keep the using directive and make sure that you don't
> use names that also live in the std:: namespace.

How about not using the 'using' directive at all? My code has become
much more readable after I stopped using it. Don't believe dissenting
opinions, they are wrong. The code *does* become more readable.

Jerry Coffin

unread,
Jul 29, 2009, 6:39:24 PM7/29/09
to
In article <R21cm.128$TB5...@read4.inet.fi>, nos...@thanks.invalid
says...

[ ... ]

> How about not using the 'using' directive at all? My code has
> become much more readable after I stopped using it. Don't believe
> dissenting opinions, they are wrong. The code *does* become more
> readable.

There are times that a using directive (or at least a using
declaration) can be useful, and there's no real alternative to it.

The canonical example is something like a sort routine. If swap has
been specialized for the type being sorted, we want to use that swap.
If swap has not been specialized for the type, we want to fall back
on using std::swap instead.

We can get that with code something like this:

using std::swap;

template <class T>
void sort(/* ... */) {

// ...
// x1 and x2 are T's.
if (x2 < x1)
swap(x1, s2);
// ...
}

The trick here is simple: if we specify std::swap, then that's what
will be used, even if T provides its own swap. On the other hand, if
we try to specify T's namespace, the code won't compile unless T
actually _does_ provide its own swap (and we don't want that
restriction -- just for example, it would then fail for all built-in
types).

The cure is pretty simple, as shown above. If there's a 'swap' in T's
namespace, argument dependent lookup will find it, and that's what
will get used. Otherwise, because of the using declaration, std::swap
will be found instead.

In the case above, I've used a using declaration, but if (for
example) we were using quite a few different things like this, a
using directive would become more convenient. Just for example, the
code above uses the less-than operator, but for genericity it should
really use a comparison function. Again, std::less<T> might be the
appropriate version (it would be equivalent to what's above) but
again, if T provides its own less(), we'd prefer to use that. In this
case there's not nearly as big a problem though, simply because
std::less<T> will use T's operator< (so all that's usually needed is
to supply operator< if ordering is at all appropriate).

--
Later,
Jerry.

red floyd

unread,
Jul 30, 2009, 2:11:48 AM7/30/09
to
Jerry Coffin wrote:
>
> There are times that a using directive (or at least a using
> declaration) can be useful, and there's no real alternative to it.
>
> The canonical example is something like a sort routine. If swap has
> been specialized for the type being sorted, we want to use that swap.
> If swap has not been specialized for the type, we want to fall back
> on using std::swap instead.
>
> We can get that with code something like this:
>
> using std::swap;
>
> template <class T>
> void sort(/* ... */) {
>
> // ...
> // x1 and x2 are T's.
> if (x2 < x1)
> swap(x1, s2);
> // ...
> }


Isn't this the one case where the user is allowed to add to std::?
That is, specializing a template in std::? Why not just specialize
std::swap<> for your type T, instead? e.g.:

class my_expensive_to_swap_class {
// ...
public:
void swap(T&);
};

template<>
std::swap<my_expensive_to_swap_class>(
my_expensive_to_swap_class& x,
my_expensive_to_swap_class& y)
{
x.swap(y);
}

// etc....

Alf P. Steinbach

unread,
Jul 30, 2009, 2:32:19 AM7/30/09
to
* red floyd:

I agree that this would be nice, and that it's even what one would choose to do
in practice.

But if there's a language lawyer nearby it may be highly provocative.

For the standard (probably through some mishap) only allows specialization of
'std' namespace classes, not routines, and so, perhaps because that arbitrary
restriction appears to be very mysterious and subtle to those who think the
standard must be perfect where it's not obviously self-contradictory, the
established Perfect Standard Code practice is to Not Do That(TM).


Cheers & hth.,

- Alf

SG

unread,
Jul 30, 2009, 2:53:16 AM7/30/09
to
On 30 Jul., 08:32, "Alf P. Steinbach" wrote:
>
> But if there's a language lawyer nearby it may be highly provocative.
>
> For the standard (probably through some mishap) only allows specialization of
> 'std' namespace classes, not routines,

Are you sure? Can you quote the standard on that?

If my memory serves me well, Scott Meyers wrote in "Effective C++"
that it is legal to specialize a function template in std::.

Cheers!
SG

James Kanze

unread,
Jul 30, 2009, 5:14:54 AM7/30/09
to

> > using std::swap;

That's what I'd generally recommend, but it doesn't work if the
class in question is actually a template; you can specialize a
function in std:: over a single type, but you can't provide an
overload which would work with a template type (officially, at
least---in practice, you almost certainly can).

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Alf P. Steinbach

unread,
Jul 30, 2009, 5:21:58 AM7/30/09
to
* SG:

> On 30 Jul., 08:32, "Alf P. Steinbach" wrote:
>> But if there's a language lawyer nearby it may be highly provocative.
>>
>> For the standard (probably through some mishap) only allows specialization of
>> 'std' namespace classes, not routines,
>
> Are you sure?

No, I made a too sweeping statement. :-)


> Can you quote the standard on that?

Yeah. �17.4.3.1/1 states that "A program may add template specializations for
any standard library template to namespace std."

And this works fine for Jerry's example (at least when fixed, it was evidently
written in haste just as my article), sorry for that over-generalization, mea culpa.

/However/, what I should have written if my memory hadn't over-generalized, was
that you cannot, within strict standard-conformance, do e.g.

namespace std {
template< typename T > void swap( MyArray<T>&, MyArray<T>& );
}

And the reason is that this is /not/ a template specialization (as Jerry's
example was) -- in particular, it's not a partial specialization.

This is an overload.


> If my memory serves me well, Scott Meyers wrote in "Effective C++"
> that it is legal to specialize a function template in std::.

He he. I think we're perhaps in the "slow zone" of the galaxy. But, our Usenet
ruminations will perhaps find their way all the way up to Top Relay. :-)


Cheers & thanks,

- Alf

James Kanze

unread,
Jul 30, 2009, 5:23:21 AM7/30/09
to

> >> using std::swap;

That's wrong. You're mixing it up with another issue.

> and so, perhaps because that arbitrary restriction appears to
> be very mysterious and subtle to those who think the standard
> must be perfect where it's not obviously self-contradictory,
> the established Perfect Standard Code practice is to Not Do
> That(TM).

The problem is when the user defined type isn't a type, but a
template. Something like:

class MyClass { /* ... */ } ;
namespace std {
void swap( MyClass& a, MyClass& b ) { /* ... */ }
}

is perfectly legal, and approved by the standard. If, on the
other hand, you have something like:

template< typename T >
class MyClass { /* ... */ } ;


namespace std {
template< typename T >

void swap( MyClass< T >& a, MyClass< T >& b )
{ /* ... */ }
}

you don't have an explicit specialization, you've defined a new
function template (which overloads with the existing one). And
that is formally forbidden (but is IMHO still the preferred
solution---since it will, in practice, work).

It's interesting, because I think with a little work, the
wording could be extended to officially allow the above. No one
has done that work, however.

Jerry Coffin

unread,
Jul 30, 2009, 2:13:30 PM7/30/09
to
In article <h4rdja$lgg$1...@news.eternal-september.org>,
no.spa...@its.invalid says...

[ ... ]

> Isn't this the one case where the user is allowed to add to std::?
> That is, specializing a template in std::? Why not just specialize
> std::swap<> for your type T, instead? e.g.:

It is a case where it's allowed, and things work just fine if the
user has done that. Keep in mind, however, that when you're writing a
template, you have essentially no control over what the user will
decide to do, and you want your template to "do the right thing"
anyway.

--
Later,
Jerry.

0 new messages