Недавно я попытался создать класс is_class
, и мне нужен был способ, чтобы компилятор различал типы перечисления и типы классов, для которых определены операторы преобразования. Поскольку классы, структуры и объединения являются единственными типами, совместимыми с функциями указателя на член, я решил, что компилятор определит, совместим ли тип, используемый для создания экземпляра шаблона is_class
, с указателями на функции-члены. После нескольких проблем я решил проверить поведение перечислений при их использовании в сочетании с указателями на члены и получил некоторые странные результаты. Следующий сегмент иллюстрирует первую причуду:
enum ENUM {};
void Test(void (ENUM::*pmem) (void))
{
/* ... */
}
Test(NULL);
При компиляции с Microsoft Visual C ++ 2010 часть указателя на член определения функции: (ENUM::*pmem)
выделено красным цветом, а при наведении указателя мыши появляется ошибка:
Error: "ENUM" is not a class type
Однако компилятор анализирует этот сегмент без каких-либо ошибок, присваивая pmem
NULL
. Мне интересно, что компилятор позволил бы увидеть, что типы перечисления не являются классами, структурами или объединениями и поэтому не могут иметь свои собственные методы.
Второй интересный момент возник при создании шаблонной функции, принимающей аргумент указатель на член, тип которого варьируется:
template<class _Ty>
void Test_Template(void (_Ty::*pmem) (void))
{
/* ... */
}
Конечно, чтобы использовать эту функцию, она должна быть явно указана:
Test_Template<ENUM>(NULL);
Однако, этот вызов выдает ошибку:
invalid explicit template argument(s) for 'void Test(void (__thiscall _Ty::* )(void))'
Я исправил эту проблему, создав дополнительный шаблон функции, прототип которого соответствовал бы любому вызову, который не соответствовал прототипу для предыдущей функции шаблона (которая включала использование многоточия).
Вопросы:
Почему перечисление совместимо с указателями на членов?
Почему существует точное совпадение при вызове не шаблонной функции Test
, в то время как компилятор генерирует ошибку для шаблона Test_Template
явной квалификации?