Почему вывод аргумента шаблона не выполняется для указателя на член-функцию?
С g++ 5.4 это
struct B {
void f() {}
};
struct D : public B {
void g() {}
};
template <class T>
void foo(void (T::*)(), void (T::*)())
{}
int main()
{
foo(&D::f, &D::g);
}
не удается из-за "выведенных конфликтующих типов для параметра" T "(" B "и" D ")". Почему T не выводится как D, будучи точным соответствием?
2 ответа
В дополнение к отличной демонстрацииVTT. Я думаю, что стандартный текст находится по адресу [expr.unary.op] / 3, выделение мое:
Результатом унарного оператора & является указатель на его операнд. Операндом должно быть lvalue или квалифицированный идентификатор. Если операндом является квалифицированный идентификатор, называющий нестатический или вариантный член m некоторого класса C с типом T, результат имеет тип "указатель на член класса C типа T" и является предварительным значением, обозначающим C:: м
Квалифицированный идентификатор, который вы использовали D::f
, но это называет функцию-член B
(Я могу вызвать правила поиска, если хотите). Итак, тип класса C
в приведенном выше абзаце, является B
, Тип поэтому разрешает void ( B::* )(void)
,
Тип &D::f
было бы void ( B::* )(void)
static_assert(::std::is_same<void ( B::* )(void), decltype(&D::f)>::value, "");
static_assert(::std::is_same<void ( D::* )(void), decltype(&D::f)>::value, ""); // error
static_assert(::std::is_same<void ( D::* )(void), decltype(&D::g)>::value, "");
Это объясняется тем, что в противном случае вы не сможете присвоить значение &D::f
к переменной void ( B::* )(void)
Тип без броска, хотя f
является членом B
или сравнить &D::f == &B::f
,
В качестве обходного пути вы можете выполнить static_cast:
foo(static_cast<void (D::*)(void)>(&D::f), &D::g);