关于一个相关但切线的问题( How to disambiguate function templates that differ only by return type? ),我想问一个与函数的返回类型不被视为函数签名的一部分这一事实有关的问题。
考虑以下代码:
#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
}上面提到的代码行会导致编译错误,因为正在对foo进行强制转换的函数类型的返回类型与函数foo的返回类型不匹配。
但是我认为函数的返回类型在函数的签名中不起作用!
按照一定的思路,既然函数签名long(&)()与foo签名相匹配,那么将foo转换成这种类型的函数就会成功。
然而,演员们并没有成功。推理哪里出错了?如果由于函数签名,强制转换不能失败,那么为什么强制转换失败?
发布于 2012-12-03 14:45:30
正确的是,返回类型并不是函数签名的一部分。
但是,它确实是函数类型的一部分,并且不允许将指针转换为不兼容的函数类型。
发布于 2012-12-03 14:52:05
返回类型是该类型的部分,尽管不用于重载解析。重要的是不要混淆术语。基本上,该类型包括参数和返回值,但在过载解析期间,不考虑返回类型。函数或函数指针的类型是调用方和被调用方之间的契约,它们必须完全同意这些条件。
从一个实际的角度来看,如果你的建议被允许的话,会发生什么。假设调用方保留空间并将指向该空间的指针传递给函数,然后函数将在该位置构造返回的对象(这实际上是一个非常常见的调用约定)。现在考虑一下,您可以执行您建议的强制转换和下面的用例
static_assert(sizeof(T1)<sizeof(T2));
T2 f();
T1 (*p)() = &f;
p(); // call现在,当编译器处理p()时,它会在某个地方保留空间,并给定它需要保留sizeof(T1)的函数的类型。然后调用函数,该函数最后调用f,该函数将sizeof(T2)字节写入导致溢出的位置。
即使大小匹配,代码也会有问题。考虑一下T1==int和T2==float在一个平台中的sizeof(int)==sizeof(float)。虽然上面的代码不会导致缓冲区溢出,但是存储在返回类型位置的位模式将是float,而不是int。
发布于 2012-12-03 16:32:29
函数的返回类型不是签名的一部分,但是为了正确调用函数指针或引用,编译器不需要知道签名。
除了参数之外,编译器还需要知道返回类型,以便为堆栈上的返回值腾出空间,或者从正确的寄存器中读取返回值,或者在给定的实现中读取调用约定所要求的任何内容。
这就是为什么返回类型是函数类型的一部分--所以类型告诉编译器它在编译时需要知道什么,这样才能发出调用函数的代码。
函数签名
long(&)()与foo的签名匹配。
long(&)()不是函数签名,而是一种类型。foo(void)是( a)函数签名的表示形式。它包括名称和参数。但是,您不需要在C++代码中指定函数签名(嗯,可能是传递给dlsym或类似的字符串)。函数签名的明确表示是给定实现中函数的错误名称。损坏方案是不标准的,它取决于实现(尽管如果不同的实现想要调用对方的库,那么它们必须使用相同的方案,因此操作系统可能会指定一个)。
https://stackoverflow.com/questions/13685262
复制相似问题