call of overloaded 'foo(short unsigned int*&)' is ambiguous

M

mathieu

Could someone please tell me what is wrong with the following -ugly-
piece of c++ code. Why when I explicititely set the template parameter
my gcc compiler start getting confused:

bla.cxx: In function 'int main()':
bla.cxx:25: error: call of overloaded 'foo(short unsigned int*&)' is
ambiguous
bla.cxx:2: note: candidates are: void foo(OutputType*) [with PixelType
= short unsigned int, OutputType = short unsigned int]
bla.cxx:10: note: void foo(PixelType*) [with PixelType
= short unsigned int]

with code:


template <class PixelType,class OutputType>
void foo(OutputType *outputCurve)
{
PixelType pt;
}

template <class PixelType>
void foo(PixelType *outputCurve)
{
foo<PixelType,PixelType>(outputCurve);
}

int main()
{
unsigned short *o = 0;
// foo(o); // ok
foo<unsigned short>(o); // not ok
return 0;
}


Thanks !
 
B

Bo Persson

mathieu said:
Could someone please tell me what is wrong with the following -ugly-
piece of c++ code. Why when I explicititely set the template
parameter my gcc compiler start getting confused:

bla.cxx: In function 'int main()':
bla.cxx:25: error: call of overloaded 'foo(short unsigned int*&)' is
ambiguous
bla.cxx:2: note: candidates are: void foo(OutputType*) [with
PixelType = short unsigned int, OutputType = short unsigned int]
bla.cxx:10: note: void foo(PixelType*) [with
PixelType = short unsigned int]

with code:


template <class PixelType,class OutputType>
void foo(OutputType *outputCurve)
{
PixelType pt;
}

template <class PixelType>
void foo(PixelType *outputCurve)
{
foo<PixelType,PixelType>(outputCurve);
}

int main()
{
unsigned short *o = 0;
// foo(o); // ok
foo<unsigned short>(o); // not ok
return 0;
}

In the call to foo<unsigned short>(o), you explicitly say that
PixelType is unsigned short.

The compiler says - what if OutputType is also unsigned short?


Bo Persson
 
A

Andrey Tarasevich

mathieu said:
Could someone please tell me what is wrong with the following -ugly-
piece of c++ code. Why when I explicititely set the template parameter
my gcc compiler start getting confused:

bla.cxx: In function 'int main()':
bla.cxx:25: error: call of overloaded 'foo(short unsigned int*&)' is
ambiguous
bla.cxx:2: note: candidates are: void foo(OutputType*) [with PixelType
= short unsigned int, OutputType = short unsigned int]
bla.cxx:10: note: void foo(PixelType*) [with PixelType
= short unsigned int]

with code:


template <class PixelType,class OutputType>
void foo(OutputType *outputCurve)
{
PixelType pt;
}

template <class PixelType>
void foo(PixelType *outputCurve)
{
foo<PixelType,PixelType>(outputCurve);
}

int main()
{
unsigned short *o = 0;
// foo(o); // ok
foo<unsigned short>(o); // not ok
return 0;
}

As you probably know, when you call a template function you are not
required to explicitly specify all template arguments. You can specify
none (in which case the compiler will try to deduce them), or you can
specify just a few of the leading arguments (in which case the compiler
will try to deduce the remaining ones).

In the first call

foo(o);

you don't specify any template arguments. The compiler considers both
versions of 'foo' template. In this case the compiler cannot use the
first version of 'foo' template as a candidate, because template
argument 'PixelType' is not deducible. The compiler is left with only
one candidate - the second version of 'foo' template - and successfully
uses it.

In the second call

foo<unsigned short>(o);

you specified one template argument. The compiler again considers both
versions of 'foo' template. This argument can be interpreted as the
first argument of the first 'foo' template (the one that was
non-deducible in the previous example). Since you specified it
explicitly, the compiler only has to deduce the second template
argument, which it can successfully do. So the first version becomes a
candidate in this case. The second version of 'foo' template is also a
candidate - with an explicitly specified argument. So now the compiler
has two candidates and both are equally good. Hence the ambiguity the
compiler is telling you about in its error messages.

However, it would be interesting to know whether C++ partial ordering
rules are supposed to resolve the ambiguity in this case. Is one of the
versions supposed to be recognized as "more specialized"? I'd say not,
based on what I see in C++98 specification. But Comeau Online compiler
seems to resolve the call in favor of the two-parameter version without
complaining about any ambiguities.
 
J

James Kanze

Could someone please tell me what is wrong with the following
-ugly- piece of c++ code. Why when I explicititely set the
template parameter my gcc compiler start getting confused:
bla.cxx: In function 'int main()':
bla.cxx:25: error: call of overloaded 'foo(short unsigned int*&)' is
ambiguous
bla.cxx:2: note: candidates are: void foo(OutputType*) [with PixelType
= short unsigned int, OutputType = short unsigned int]
bla.cxx:10: note: void foo(PixelType*) [with PixelType
= short unsigned int]

The compiler isn't confused; it's just doing what the standard
requires:).
with code:
template <class PixelType,class OutputType>
void foo(OutputType *outputCurve)
{
PixelType pt;
}
template <class PixelType>
void foo(PixelType *outputCurve)
{
foo<PixelType,PixelType>(outputCurve);
}
int main()
{
unsigned short *o = 0;
// foo(o); // ok
foo<unsigned short>(o); // not ok
return 0;
}

OK. You have two function templates named foo, which will be
considered each time you invoke a function named foo; overload
resolution will determine which one is chosen. Strictly
speaking, function overload chooses between functions, not
between function templates; when you call a function for which
there are function templates, the compiler tries to deduce the
template arguments for each function template, and if it
succeeds, it adds the instantation (the instantiation of a
function template is a function) to the overload set.

In the first case, foo(o), template argument deduction fails for
the first function template; the compiler cannot deduce the type
of PixelType, so no function is added. It succeeds for the
second, with unsigned short for PixelType, the the function
foo<unsigned short>( unsigned short* ) is added to the overload
set. Since the overload set only contains a single function,
there is no ambiguity.

In the second case, where you call foo<unsigned short>, the
procedure is exactly the same. Except that argument deduction
works for both of the functions; for the first, it gives an
instantiation of foo<unsigned short, unsigned short>, and for
the second, an instantiation of foo<unsigned short>. (For the
second, there's really not much to deduce in the usual sense of
the word, but formally, deduction takes place, and the results
are added to the overload set.) The result is that you end up
with two functions with the same parameter, which results in an
ambiguity from overload resolution.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top