- So why I cannot directly define conversion for my class using the type
int(*)(int, int)
but I can with a type alias?
The grammar for the "operator
TYPE" name of a conversion function is much more restricted than a more general declarator or type-id. It doesn't allow parentheses at all, only a type specifier (like a type alias name, unsigned int
, a class name, etc.), combinations of the *
, &
, &&
, const
and volatile
tokens, and [[
attributes]]
. I can't say exactly why, but complicated declarations like that are tricky to write, read, and parse. Maybe there's a potential ambiguity in some case if more were allowed, or maybe they just didn't want to require compilers to have to figure this one out.
Also, if it were allowed, maybe the form would be operator int (*())(int, int);
and not operator (int(*)(int, int))()
? Or maybe that doesn't make sense either. See? Tricky.
- Why I get value
1
in the first statement which is erroneous and get it correct in the second statement using parenthesis?
Function call syntax has higher precedence than C-style cast. So
(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
Expression (1) or (2) evaluates by first creating a temporary Foo
. It's followed by function call syntax, and Foo
doesn't define an operator()
, but C++ will also check if it implicitly converts to a pointer or reference to function and it does, so the (5, 7)
does the implicit conversion and calls the resulting pointer to add
, giving 12. This is cast to the function pointer type, which has implementation-defined results. There is no operator<<
declared for function pointers, but there is one for bool
, and a function pointer can implicitly convert to bool
. Presumably the result of the strange cast was not a null pointer value, so the end result is true
, and you see the value 1
. (If you had done std::cout << std::boolalpha
earlier, you should see true
or an appropriate translation instead.)
One piece of this, besides the operator precedence misunderstanding, is the dangers of a C-style cast, which can do very many different things, some not usually intended. Use static_cast<int(*)(int,int)>(Foo())(5,7)
instead, and everything's fine. Or if we accidentally typed static_cast<int(*)(int,int)>(Foo()(5,7))
instead, the compiler gives an error about converting from int
to int(*)(int,int)
, since only reinterpret_cast
or C-style cast may do that.
- I get the warning from first statement:
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
Even though the C-style cast forces the conversion from int
to function pointer to be valid, the compiler is warning that int
doesn't have enough bytes to represent a function pointer. It's assuming the int
value earlier came from casting a function pointer to some numeric type, and this is meant to convert back, but whenever it was converted from a type large enough to int
, the pointer value was lost.