jeudi 16 avril 2020

return-value deduction for non-static method pointers

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 here
test_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?

Aucun commentaire:

Enregistrer un commentaire