Похоже, у вас есть два тонких фактора, которые работают против вас. Во-первых, преобразование из int (X::*)()
в int (Y::*)()
неявно , поэтому часто его можно использовать, не задумываясь. Часто. Но в вашем сообщении об ошибке упоминается «вывод / замена аргумента».
Во время вывода аргумента шаблона неявные преобразования не считаются . Таким образом, в этом контексте предоставленный вами аргумент типа int (X::*)()
не соответствует ожидаемому int (Y::*)()
. (Является ли это несоответствие правильным или нет, я оставлю это другим. Оно существует в g cc и clang.) Если бы вы явно указали аргумент шаблона, выведение аргумента не понадобилось бы, и вы перешли бы к шагу, на котором выполняются неявные преобразования.
Простой подход к предоставлению аргумента шаблона не подходит для вашего контекста, но он обеспечивает подтверждение концепции.
_call<int>(&T::print); // Specify that the return type must be `int`
Указав int
, аргумент шаблона не нужно выводить. Тем не менее, это ограничивает ваши возможности, в значительной степени побеждая точку вашего шаблона. К счастью, мы можем сделать лучше. Мы можем сказать компилятору, как «вывести» аргумент шаблона. (Я использовал кавычки, потому что это не официальный шаг вывода шаблона.)
_call<decltype(t.print())>(&T::print); // The desired generic return type
Я думал, что возвращаемое значение метода, так сказать, не влияет на его "идентификатор".
Под "идентификатором" вы, вероятно, подразумеваете " подпись "? Это правда, что сигнатура (не шаблонной) функции не включает тип возвращаемого значения, но вы имеете дело с типами, а не с сигнатурами. тип указателя функции включает в себя как типы его параметров, так и тип возвращаемого значения.