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):

  1. substitute explicit template arguments template parameters in function declaration.

  2. for each function parameter still involves @ least 1 template parameter, compare corresponding function argument function parameter, (possibly) deduce template parameters.

  3. 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 a identical a (after type a transformed described above). however, there 3 cases allow difference:

  • if original p reference type, deduced a (i.e., type referred reference) can more cv-qualified transformed a.

  • the transformed a can pointer or pointer member type can converted deduced a via qualification conversion (4.4).

  • if p class , p has form simple-template-id, transformed a can derived class of deduced a. likewise, if p pointer class of form simple-template-id, transformed a can pointer derived class pointed deduced a.

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

Popular posts from this blog

c# - How Configure Devart dotConnect for SQLite Code First? -

java - Copying object fields -

c++ - Clear the memory after returning a vector in a function -