Strange behavior with templates and G++
Jonathan Wakely
jwakely.gcc@gmail.com
Thu Feb 17 16:30:00 GMT 2011
On 17 February 2011 13:16, Axel Freyn wrote:
> On Thu, Feb 17, 2011 at 12:22:53PM +0000, Jonathan Wakely wrote:
>> [Moved from the gcc list]
>>
>> On 17 February 2011 11:03, Pascal Francq wrote:
>> > Hi,
>> > While compiling the following code, I got an error :
>> >
>> >
>> > template<class C> class Super
>> > {
>> > public:
>> > Super(void) {}
>> > void Test(C*) {}
>> > };
>> >
>> > class A
>> > {
>> > public:
>> > A(void) {}
>> > };
>> >
>> > class A1 : public A
>> > {
>> > public:
>> > A1(void) : A() {}
>> > };
>> >
>> > class A2 : public A
>> > {
>> > public:
>> > A2(void) : A() {}
>> > };
>> >
>> > class Super2 : public Super<A1>, public Super<A2>
>> > {
>> > public:
>> > Super2(void) {}
>> > };
>> >
>> > void Test(void)
>> > {
>> > Super2 T;
>> > A1* ptr;
>> > T.Test(ptr);
>> > }
>> >
>> >
>> > The compiler gives me the following error for the Test() function:
>> > error: request for member ‘Test’ is ambiguous
>> > error: candidates are: void Super<C>::Test(C*) [with C = A2]
>> > error: void Super<C>::Test(C*) [with C = A1]
>> > But here the call refers clearly to the second method. The error still appears
>> > if A1 and A2 do not inherit from a same root class. If I replace the code with
>> > an explicit call it works:
>> > T.Super<A1>::Test(ptr)
>> > But this make the code less cleaner.
>> >
>> > Is this a problem related to a misunderstood concept from me, a wrong
>> > implementation or a technical problem of g++ ?
>>
>>
>> The ambiguity has nothing to do with templates, the code can be reduced to:
>>
>> class A1
>> {
>> public:
>> void Test(A1*) {}
>> };
>>
>> class A2
>> {
>> public:
>> void Test(A2*) {}
>> };
>>
>> class Super2 : public A1, public A2
>> {
>> };
>>
>> void Test(void)
>> {
>> Super2 T;
>> A1* ptr;
>> T.Test(ptr);
>> }
>>
>> This is covered by 10.2 [class.member.lookup] in the C++ standard,
>> which says that a name is ambiguous if found in more than one base
>> class. That makes the lookup ill-formed, before overload resolution
>> is attempted.
>
> In addition: it is not necessary to use everywhere an explicit call.
> You can import the function by adding "using"-definitions. With:
> class Super2 : public A1, public A2
> {
> public:
> using A1::Test;
> using A2::Test;
> };
> you can call T.Test(ptr) directly, and C++ will do correct overload
> resolution -- both with and without templates
Right, in that case name lookup finds two overloads of "Test" without
looking in any base classes, then overload resolution selects the
right one.
More information about the Gcc-help
mailing list