Это не ошибка (насколько я могу судить) и не имеет ничего общего с decltype
. Проблема в том, что setGreen
является не виртуальной функцией-членом BaseClass
, и, поскольку вы не объявляли такую функцию повторно в TestClass
, тип:
&TestClass::setGreen
есть:
void (BaseClass::*)(int)
... и поэтому у вас есть конфликт параметров шаблона в экземпляре шаблона HTestSet
.
Я не нашел стандартную цитату для этого лучше, чем пример в [expr.unary.op # 3] :
Результатом унарного оператора &
является указатель на его операнд. Операндом должно быть lvalue или qualid-id . Если операндом является квалифицированный идентификатор с именем нестатического или вариантного члена m
некоторого класса C
с типом T
, результат имеет тип «указатель на член класса C
типа T
”и является prvalue, обозначающим C::m
. [...]
struct A { int i; };
struct B : A { };
... &B::i ... // has type int A::*
Использование f
в начале вашего main
работает только потому, что void (BaseClass::*)(int)
может быть неявно преобразовано в void (TestClass::*)(int)
, в этом случае [conv.mem # 2] :
Значение типа «указатель на член B типа cv T», где B - тип класса, может быть преобразовано в значение типа «указатель на член D типа cv T», где D - это тип производный класс ([class.derived]) из B. [...] Поскольку результат имеет тип «указатель на член D типа cv T», косвенное обращение через него с объектом D является допустимым. Результат такой же, как если бы он направлял через указатель на член B субобъект B из D.