Я не буду описывать, что означает int C::*
, поскольку @Charles Bailey уже сделал это очень хорошо. Однако я отвечу на ваш вопрос:
(...) почему использование "int C :: *" допустимо в функции test ()
определение?
Ключевым моментом является то, что использование int C::*
(указатель на член типа int
) допустимо тогда и только тогда, когда C
является типом класса. В противном случае тип int C::*
является плохо сформированным.
Вот почему у вас есть
template<typename C> static One test(int C::*);
и, скорее всего, где-то ниже
template <typename> static Two test(...);
static const bool value = sizeof(test<T>(0)) == 1;
Когда компилятор видит test<T>(0)
, он проверяет кандидатов на test
. Находит два:
template<typename C> static One test(int C::*);
template <typename> static Two test(...);
Первый имеет приоритет над вторым, потому что 1) они оба являются шаблонными функциями и 2) многоточие ищется последним. Если первый плохо сформирован (т. Е. тогда и только тогда, когда C
не является типом класса), то он просто отбрасывается и вторая перегрузка принимается. Это поведение называется SFINAE (для ошибки замены не ошибка).
Проверяя размер возвращаемого типа (помните, что sizeof(char)
всегда равен 1), вы можете оценить во время компиляции, что взято test
, т.е. * является ли T
типом класса или нет.