Why cast a function to a function type that is identical except for the return type?

Possible duplicate:
Is part of the return type a function signature?

In response to a related but tangent question ( How do I resolve the ambiguity of function templates that differ only in return type? ), I would like to ask a question related to the fact that the return type of a function is not considered part of the function signature.

Consider the following code:

#include <iostream> int foo() { return 0; } int main() { long n = static_cast<long(&)()>(foo)(); // Error: incorrect return type int p = static_cast<int(&)()>(foo)(); // Compiles just fine } 

The line of code noted above leads to a compilation error, since the return type of the type of the function to which foo is executed does not match the return type of the foo function.

But I thought that the return type of the function does not play a role in the signature of the function!

According to a certain line of thinking, since the signature of the function long(&)() corresponds to the signature of foo , casting the function foo to a function of this type must be successful.

However, the cast is not performed. Where is the reasoning going wrong? If the cast cannot fail due to the signature of the function, then why doesn't casting work?

+1
source share
4 answers

You are correct that the return type is not part of the function signature.

However, it is part of a function type, and you are not allowed to convert pointers to incompatible function types.

+8
source

The return type is , but is not used to allow congestion. It is important not to confuse the terms. In principle, a type includes arguments and a return value, but when overload is resolved, the return type is not considered. The type of function or function pointer is a contract between the caller and the called party, and they must fully agree with the conditions.

From a practical point of view, think about what will happen if what you offer is allowed. Imagine a calling agreement in which the caller reserves the space and passes a function to a pointer to that space, then the function will build the return object in this place (this is actually a very ordinary agreement). Think now that you have been allowed to complete your proposed throw and the following use case

 static_assert(sizeof(T1)<sizeof(T2)); T2 f(); T1 (*p)() = &f; p(); // call 

Now that the compiler processes p() , it reserves a place somewhere and sets the type of function that it should reserve sizeof(T1) . It then calls a function that ends with a call to f , which writes sizeof(T2) bytes to the location, causing an overflow.

Even if the sizes match, the code will be problematic. Consider T1==int and T2==float in the platform, where sizeof(int)==sizeof(float) . Although the above code will not cause a buffer overflow, the bitpatter stored in the return type location will have a float value, not an int value.

+4
source

The return type of the function is not part of the signature, but the signature does not match what the compiler needs to know in order to properly call the function referenced by the pointer to the function or link.

Like parameters, the compiler must know the return type so that it can create space for the return value on the stack or read the return value from the correct register (s) or any other requirements agreement in this implementation.

This is why the return type is part of the function type, so the type tells the compiler what it needs to know at compile time in order to emit code to call the function.

the signature of the long(&)() function corresponds to the signature foo

long(&)() not a function signature, it is a type. foo(void) is (a representation of) the signature of the function. It includes a name and parameters. But you never need to specify the signature of the function in C ++ code (well, perhaps as a string passed to dlsym or similar). The final representation of the function signature is the garbled function name in this implementation. The manipulating scheme is not standard, it is right up to the implementation (although if different implementations want to call each other in libraries, then they must use the same scheme, so the OS can specify it).

+1
source

The return type of a function is considered to be part of its signature (and its type). However, it is permitted to assign pointers to variables with different return types if the return types are "covariant."

0
source

All Articles