Prev: return value optimization vs. returning a boost::shared_ptr of container
Next: STL::glice vs cstdio
From: naikrosh on 20 Jun 2010 00:34 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 20 Jun 2010 04:59 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 20 Jun 2010 04:58 "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! ]
|
Pages: 1 Prev: return value optimization vs. returning a boost::shared_ptr of container Next: STL::glice vs cstdio |