From: naikrosh on
struct Base {
int b;
};

struct Derived : Base {
int d;
};

template<typename Obj>
bool foo_mem(Obj& obj_, int Obj::* mem) {
return true;
}

int main() {
Derived d;
foo_mem(d, &Derived::b); // is Obj ambiguous ?
foo_mem(d, &Base::b); // is Obj ambiguous ?
return 0;
}

Gcc (4.1.1), Clang and Visual C++ report this code to be ambiguous.

- Gcc Error: no matching function for call to 'foo_mem(Derived&, int
Base::*)'

- VC++ Error: error C2782: 'bool foo_mem(Obj &,int Obj::* )' :
template parameter 'Obj' is ambiguous

- Clang Error : no matching function call to foo_mem
But what the "reference" compiler front end (EDG) accepts it.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Johannes Schaub (litb) on
naikrosh(a)gmail.com wrote:

> struct Base {
> int b;
> };
>
> struct Derived : Base {
> int d;
> };
>
> template<typename Obj>
> bool foo_mem(Obj& obj_, int Obj::* mem) {
> return true;
> }
>
> int main() {
> Derived d;
> foo_mem(d, &Derived::b); // is Obj ambiguous ?
> foo_mem(d, &Base::b); // is Obj ambiguous ?
> return 0;
> }
>
> Gcc (4.1.1), Clang and Visual C++ report this code to be ambiguous.
>
> - Gcc Error: no matching function for call to 'foo_mem(Derived&, int
> Base::*)'
>
> - VC++ Error: error C2782: 'bool foo_mem(Obj &,int Obj::* )' :
> template parameter 'Obj' is ambiguous
>
> - Clang Error : no matching function call to foo_mem
> But what the "reference" compiler front end (EDG) accepts it.
>
>

Yes this is ambiguous. "Obj" is deduced to two different types. In the first
parameter, it yields "Derived", but in the second parameter it yields "Base"
because "b" is a direct member of Base.

This type of bug can be fixed by making one parameter a non-deduced context,
thus aquiring the type of the other parameter found by deduction:

template<typeame Obj>
bool foo_mem(typename identity<Obj>::type &obj_, int Obj::*mem);

That way, the "Derived" argument is converted to a "Base&" when passed to
the function. You can have it the other way around

template<typeame Obj>
bool foo_mem(Obj &obj_,
int identity<Obj>::type::*mem);

This way "Obj" will be "Derived" and the passed member pointer will be
converted from "int Base::*" to "int Derived::*" when passed. I think this
is the more superior way because it keeps the arguments as most derived as
it can.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on
"naikrosh(a)gmail.com" <naikrosh(a)gmail.com> writes:

> struct Base {
> int b;
> };
>
> struct Derived : Base {
> int d;
> };
>
> template<typename Obj>
> bool foo_mem(Obj& obj_, int Obj::* mem) {
> return true;
> }
>
> int main() {
> Derived d;
> foo_mem(d, &Derived::b); // is Obj ambiguous ?
> foo_mem(d, &Base::b); // is Obj ambiguous ?
> return 0;
> }

That template argument deduction fails in the second instance - that is,
for the call:

foo_mem(d, &Base::b);

is clear. The reason for this is that, from the first function call
argument, Obj is deduced to Derived and, from the second, it is deduced
to Base. The relevant clause here is:

[temp.deduct.type] �14.8.2.4/2:
"Type deduction is done independently for each P/A pair, and the
deduced template argument values are then combined. [...] if
different pairs yield different deduced values [...] template
argument deduction fails."

What might be surprising to you, however, is that it is essentially the
same for the first call:

foo_mem(d, &Derived::b);

Here, likewise, template argument deduction produces [Obj = Base] from
the second function call argument. That is, even though you have given
it &Derived::b, it sees &Base::b for the purposes of TAD since b is,
indeed, directly a defined member of Base.

Note, also, that the situation is not improved by:

struct Derived : Base {
int d;
using Base::b;
};

*Both* attempted instantiations will fail with the same diagnostic
(gcc):

error: no matching function for call to �foo_mem(Derived&, int
Base::*)�
^^^^

Regards

Paul Bibbings


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]