I was toying around with function pointers to non-static methods and stumbled upon some GCC-messages that don't quite make sense to me. Let's maybe look at some code:
#include<iostream>struct X{ int print() const { std::cout << "hello"; return 0; } };struct Y: public X{};template<class T>struct print_one{ const T& t; print_one(const T& _t): t(_t) {} template<class Something> void _call(Something (T::*fct)() const) const { std::cout << (t.*fct)() << '\n'; } void do_print() const { _call(&T::print); }};int main(){ X x; Y y; print_one<X>(x).do_print(); //print_one<Y>(y).do_print();}
I was ready to see this fail because I thought the return value of a method does not contribute to its "ID" so to say. However, this compiles (gcc-9 --std=c++17
) and works fine.
But, if I instanciate print_one
with a Y
(uncomment last line in main()
) things go south:
test_ptr.cpp: In instantiation of 'void print_one<T>::do_print() const [with T = Y]':test_ptr.cpp:28:28: required from heretest_ptr.cpp:19:27: error: no matching function for call to 'print_one<Y>::_call(int (X::*)() const) const' 19 | void do_print() const { _call(&T::print); } | ^~~~~test_ptr.cpp:14:8: note: candidate: 'template<class Something> void print_one<T>::_call(Something (T::*)() const) const [with Something = Something; T = Y]' 14 | void _call(Something (T::*fct)() const) const | ^~~~~test_ptr.cpp:14:8: note: template argument deduction/substitution failed:test_ptr.cpp:19:27: note: mismatched types 'const Y' and 'const X' 19 | void do_print() const { _call(&T::print); } | ^~~~~
In particular with Something = Something
seems weird to me. Further, the whole thing works if I explicitly give the template instanciation like so: _call<int>(&T::print)
.
So, the questions would be: why can GCC deduce the template argument Something
although it's not part of the signature of the print
method and why does the deduction fail when confronted with a class derived from the class defining the actual method?