Во-первых, когда вы делаете &class::member
, тип результата всегда основан на классе, в котором фактически объявлен член. Вот как унарный &
работает в C ++.
Во-вторых, код не компилируется из-за сбоя вывода аргумента шаблона. Из первого аргумента он выводит desttype = derived
, а из второго он выводит desttype = base
. Это то, что делает сборку неудачной. Правила вывода аргументов шаблона в C ++ не учитывают тот факт, что this
может быть преобразовано в тип base *
. Более того, можно утверждать, что вместо преобразования типа this
в base *
правильным будет преобразование &derived::foo
из указателя на базовый элемент в тип указателя на производный член. Оба подхода одинаково жизнеспособны (см. Ниже).
В-третьих, указатели членов в C ++ подчиняются правилам contra-variance , что означает, что указатель на член базового класса может быть неявно преобразован в указатель на член производного класса. В вашем случае все, что вам нужно сделать, это помочь компилятору пройти вывод аргумента шаблона, указав аргумент явно, и код должен скомпилировать
connect<derived>(this, &derived::foo);
Вышеприведенное должно скомпилироваться из-за противоположного отклонения от &derived::foo
указателя, даже если это указатель на base
член. В качестве альтернативы вы можете сделать
connect<base>(this, &derived::foo);
Это также должно компилироваться из-за ковариации из this
указателя.
Вы также можете использовать явное приведение к фактическим аргументам (как вы упомянули в вопросе), чтобы преодолеть неоднозначность вывода, но, на мой взгляд, в этом случае явно указанный аргумент шаблона выглядит лучше.