在下面的代码中,函数指针和我认为的“函数引用”似乎具有相同的语义:
#include <iostream>
using std::cout;
void func(int a) {
cout << "Hello" << a << '\n';
}
void func2(int a) {
cout << "Hi" << a << '\n';
}
int main() {
void (& f_ref)(int) = func;
void (* f_ptr)(int) = func;
// what i expected to be, and is, correct:
f_ref(1);
(*f_ptr)(2);
// what i expected to be, and is not, wrong:
(*f_ref)(4); // i even added more stars here like (****f_ref)(4)
f_ptr(3); // everything just works!
// all 4 statements above works just fine
// the only difference i found, as one would expect:
// f_ref = func2; // ERROR: read-only reference
f_ptr = func2; // works fine!
f_ptr(5);
return 0;
}
我在Fedora / Linux中使用了gcc版本4.7.2
更新
我的问题是:
f_ptr = &func;
有效?因为func应该衰减为指针?f_ptr = &&func;
不起作用(隐式转换自void *
)答案 0 :(得分:13)
函数和函数引用(即那些类型的 id-expressions )几乎立即衰减到函数指针中,因此表达式func
和f_ref
实际上成为你的函数指针案件。如果您愿意,也可以致电(***func)(5)
和(******f_ref)(6)
。
在您希望&
- 运算符像应用于函数本身一样工作的情况下,最好使用函数引用,例如&func
与&f_ref
相同,但&f_ptr
是其他内容。
答案 1 :(得分:13)
“为什么函数指针不需要解除引用?”
因为函数标识符本身实际上是指向函数的指针:
4.3功能指针转换
§1函数类型T
的左值可以转换为“指向T
的指针”的右值。结果是指向函数的指针。
“为什么取消引用函数引用不会导致错误?”
基本上,您可以将引用定义为定义别名(替代名称)。即使在 8.3.2 References 中的标准中,在部分寻址中创建对象的引用,您会发现:
“引用可以被视为对象的名称。”
所以当你定义一个引用时:
void (& f_ref)(int) = func;
它使您能够在可能使用f_ref
的任何地方使用func
,这就是为什么:
f_ref(1);
(*f_ref)(4);
与直接使用func
的方式完全相同:
func(1);
(*func)(4);
答案 2 :(得分:2)
请参阅here。
地址运算符的行为与您期望的一样,因为它指向一个函数但无法分配。当用作rvalues时,函数将转换为函数指针,这意味着您可以多次取消引用函数指针并返回相同的函数指针。
答案 3 :(得分:0)
由于这里的其他人给出了很好的答案,因此没有任何答案可以解释为什么f_ptr = &&func;
不起作用。将运算符&
的地址应用于变量/函数时,将获得其地址。地址本身是一个r值/一个临时变量。您不能使用临时地址。
但是似乎存在类型错误。消息implicit conversion from void*
专门针对此代码进行编译。我猜您正在使用GCC / Clang。 GCC / Clang提供了获取&&label
之类的标签地址的功能。结果值的类型为void*
。其他编译器将输出类似cannot take address of temporary
或invalid syntax
的内容。在使用这些编译器时,在特殊情况下可能会隐藏此类错误而没有任何警告:
int main() {
int foo = 42;
foo:;
void* a = &foo; // take the address of a variable/function
void* b = &&foo; // take the address of a label
std::cout << *(int*)a << '\n';
goto *b;
};
但是谁会给所有相同的名字命名?