c++ - can't pass function pointer to method in parent class through a variadic function--compiler bug? -
say have 2 structures, generic_a , generic_b. generic_b derived generic_a. why when generic_b tries access method in parent, generic_a, generates following error:
test2.cpp: in function 'int main()': test2.cpp:26: error: no matching function call 'case1(void (generic_a::*)()' this code, compiled using gcc version 4.4.6, replicates problem:
#include <stdio.h> struct generic_a { void p1() { printf("%s\n", __pretty_function__); }; }; struct generic_b : public generic_a { void p2() { printf("%s\n", __pretty_function__); }; }; template <class t,class... args> void case1( void (t::*p)(args...) ) { printf("%s\n", __pretty_function__); } template <class t> void case2( void (t::*p)() ) { printf("%s\n", __pretty_function__); } main() { //generates error case1<generic_b>(&generic_b::p1); //compiles fine case2<generic_b>(&generic_b::p1); } the apparent difference between 2 function calls case1() has template argument parameter, , case2() doesn't. shouldn't both allow pass function pointer method in generic_b's parent (ie &generic_b::p1)?
also, casting function pointer in case1 seems resolve error:
case1<generic_b>( (void (generic_b::*)()) &generic_b::p1); what going on?
this tricky, turns out g++ correct.
first, type of expression &generic_b::p1 void (generic_a::*)(). compiler uses generic_b:: qualify name lookup , finds member of generic_a. expression type depends on definition of member found, not type used within qualified-id.
but it's legal have
void (generic_b::*member)() = &generic_b::p1; since there implicit conversion void (generic_a::*)() void (generic_b::*)().
whenever function template used function call, compiler goes through 3 basic steps (or attempts to):
substitute explicit template arguments template parameters in function declaration.
for each function parameter still involves @ least 1 template parameter, compare corresponding function argument function parameter, (possibly) deduce template parameters.
substitute deduced template parameters function declaration.
in case, have function template declaration
template <class t,class... args> void case1( void (t::*p)(args...) ); where template parameters t , args, , function call expression
case1<generic_b>(&generic_b::p1) where explicit template argument generic_b , function argument &generic_b::p1.
so step 1, substitute explicit template argument:
void case1( void (generic_b::*p)(args...) ); step 2, compare parameter types , argument types:
the parameter type (p in standard section 14.8.2) void (generic_b::*)(args...). argument type (a) void (generic_a::*)().
c++ standard (n3485) 14.8.2.1p4:
in general, deduction process attempts find template argument values make deduced
aidenticala(after typeatransformed described above). however, there 3 cases allow difference:
if original
preference type, deduceda(i.e., type referred reference) can more cv-qualified transformeda.the transformed
acan pointer or pointer member type can converted deducedavia qualification conversion (4.4).if
pclass ,phas form simple-template-id, transformedacan derived class of deduceda. likewise, ifppointer class of form simple-template-id, transformedacan pointer derived class pointed deduceda.
so type deduction allows implicit conversions involving const / volatile and/or derived-to-base conversions, implicit conversions of pointers members not considered.
in case1 example, type deduction fails, , function not match.
unfortunately, there's no way explicitly specify template parameter pack args should substituted empty list. discovered, can working explicitly doing necessary pointer member function conversion yourself, though it's otherwise valid implicit conversion.
Comments
Post a Comment