- Так почему я не могу напрямую определить преобразование для своего класса, используя тип
int(*)(int, int)
, но могу определить псевдоним типа?
Грамматика для "operator
TYPE" имени функции преобразования гораздо более ограничено, чем более общий декларатор или type-id . Он вообще не допускает скобок, только спецификатор типа (например, псевдоним типа, unsigned int
, имя класса и т. Д. c.), Комбинации *
, &
, &&
, const
и volatile
токены и [[
атрибуты ]]
. Я не могу точно сказать, почему, но такие сложные заявления сложно написать, прочитать и проанализировать. Возможно, в некоторых случаях существует потенциальная неоднозначность, если разрешено больше, или, может быть, они просто не хотят требовать, чтобы компиляторы выяснили это.
Кроме того, если бы было разрешено, может быть форма будет operator int (*())(int, int);
, а не operator (int(*)(int, int))()
? Или, может быть, это тоже не имеет смысла. Видеть? Tricky.
- Почему я получаю значение
1
в первом утверждении, которое является ошибочным, и получаю его правильно во втором утверждении с использованием скобок?
Синтаксис вызова функции имеет более высокий приоритет , чем C стиль приведения. Так что
(int(*)(int, int))Foo()(5, 7) // (1)
(int(*)(int, int)) (Foo()(5, 7)) // (2), same as (1)
((int(*)(int, int))Foo()) (5, 7) // (3), not the same
Выражение (1) или (2) оценивает, сначала создав временный Foo
. За ним следует синтаксис вызова функции, и Foo
не определяет operator()
, но C ++ также проверит, неявно ли он преобразуется в указатель или ссылку на функцию, и делает, так что (5, 7)
выполняет неявное преобразование и вызывает результирующий указатель на add
, давая 12. Это приведено к типу указателя функции, который имеет результаты, определенные реализацией. Для указателей на функции не объявлено operator<<
, но есть для bool
, и указатель на функцию может неявно преобразовываться в bool
. Предположительно, результатом странного приведения было не нулевое значение указателя, поэтому конечный результат равен true
, и вы видите значение 1
. (Если вы сделали std::cout << std::boolalpha
ранее, вы должны увидеть true
или соответствующий перевод вместо этого.)
Одним из элементов этого, помимо недопонимания приоритета оператора, является опасность стиля C бросок, который может делать очень много разных вещей, некоторые обычно не предназначены. Вместо этого используйте static_cast<int(*)(int,int)>(Foo())(5,7)
, и все в порядке. Или, если мы случайно набрали static_cast<int(*)(int,int)>(Foo()(5,7))
, компилятор выдает ошибку о преобразовании из int
в int(*)(int,int)
, поскольку это может сделать только приведение в стиле reinterpret_cast
или C.
- Я получаю предупреждение от первого оператора:
Description Resource Path Location Type cast to pointer from integer of different size [-Wint-to-pointer-cast] main.cpp /MyCppProj line 31 C/C++ Problem
Даже если приведение в стиле C заставляет преобразование из int
в указатель на функцию, чтобы быть действительным, компилятор предупреждает, что int
не имеет достаточно байтов для представления указателя на функцию. Предполагается, что значение int
ранее было получено от приведения указателя функции к какому-либо типу цифр c, и это предназначено для обратного преобразования, но всякий раз, когда оно преобразовывалось из достаточно большого типа в int
, значение указателя терялось. .