Почему нельзя сравнить указатель функции с функцией шаблона без явного имени функции & on?
рассмотрим следующий код:
void func(int) {}
template<typename T> void templatedFunc(T) {}
int main()
{
void (*p)(int) = func;
bool test1 = p==func;
//bool test2 = p==templatedFunc<int>; // compilation error
bool test3 = p==&templatedFunc<int>; // but this works
}
Если раскомментировать test2
line и попробуйте скомпилировать код с помощью g++, вы получите следующую ошибку:
test.cpp: In function ‘int main()’:
test.cpp:8:21: error: assuming cast to type ‘void (*)(int)’ from overloaded function [-fpermissive]
bool test2 = p==templatedFunc<int>; // compilation error
^~~~~~~~~~~~~~~~~~
Я получаю этот результат на G++ 5.3.0 и 6.2.0. В то же время компиляция с clang++ 3.6.0 выполняется без предупреждений.
какой компилятор правильный в соответствии со стандартом здесь-g++, который дает ошибку или clang++, который не делает?
и если g++ прав, то почему существует ли такая асимметрия с нормальными функциями против шаблонных функций относительно необходимости явного адреса оператора?
1 ответов
это ошибка gcc, и вы находитесь в угловом случае, в стандарте C++,адрес перегруженной функции §13.4 ([окончен.over] / 1):
использование перегруженного имени функции без аргументов разрешается в определенных контекстах функции, a указатель на функцию или указатель на функцию-член для определенной функции из набора перегрузок. Функция имя шаблона считается именем набора перегруженных функций в таких контекстах. Функция выбранный это тот тип которого совпадает с типом функции конечного типа в контексте. [ Отмечать: То есть класс, членом которого является функция, игнорируется при сопоставлении указателя на функцию-член тип. - конец Примечание ] цель может быть:
(1.1) - инициализируемый объект или ссылка(8.5, 8.5.3, 8.5.4),
(1.2) - левая сторона задания (5.18),
(1.3) - параметр функции (5.2.2),
(1.4)-параметр определяемого пользователем оператора (13.5),
(1.5) - возвращаемое значение функции, функции оператора или преобразования (6.6.3),
(1.6) - явное преобразование типов (5.2.3, 5.2.9, 5.4) или
(1.7) - не тип шаблона-параметр (14.3.2).
перегруженного имени функции может предшествовать оператор&. Перегруженное имя функции не должно использовать без аргументов в контексты, отличные от перечисленных. [ Примечание: любой избыточный набор скобок окружающие перегруженного имени функции игнорируется (5.1). - конец Примечания ]
вы видите, чего не хватает в списке от (1.1) до (1.7)... встроенные операторы!
если вы объявите перегрузку operator ==
оба gcc не будут жаловаться на сравнение, более того, вам не нужно явно специализировать функцию шаблона:
void func(int) {}
template<class T>
void templatedFunc(T) {}
struct s{};
bool operator==(s, void(*)(int)){return false;}
int main()
{
void (*p)(int) = templatedFunc;
bool test1 = p==func;
bool test2 = s{} == templatedFunc<int>; // no error - no overload resolution
bool test3 = s{} == templatedFunc; // no error - overload resolution
bool test4 = p == templatedFunc<int>; // gcc error, but not an error -
// no overload resolution
//bool test5 = p == templatedFunc; // error - overload resolution not
// performed for built-int operators
}
test2
и test3
компилируется с GCC. test4
не компилируется на GCC, но нет разрешения перегрузки, вы явно специализированные функции. Он действительно должен компилироваться. test5
не компилируется, как указано в стандарте. В этом случае gcc выдает то же самое сообщение об ошибке, что и для test4
. Это, безусловно, ошибка gcc.