【问题标题】:Function pointer vs Function reference函数指针与函数引用
【发布时间】:2013-10-12 14:10:24
【问题描述】:

在下面的代码中,函数指针和我认为的“函数引用”似乎具有相同的语义:

#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

更新

我的问题是:

  1. 为什么函数指针不需要解引用?
  2. 为什么取消引用函数引用不会导致错误?
  3. 在任何情况下我必须使用其中一种吗?
  4. 为什么f_ptr = &amp;func; 有效?既然 func 应该被衰减成一个指针?
    虽然f_ptr = &amp;&amp;func; 不起作用(从void * 隐式转换)

【问题讨论】:

    标签: c++ function pointers reference function-pointers


    【解决方案1】:

    函数和函数引用(即这些类​​型的 id-expressions)几乎立即衰减为函数指针,因此表达式 funcf_ref 在您的情况下实际上成为函数指针。如果您愿意,也可以拨打(***func)(5)(******f_ref)(6)

    如果您希望 &amp;-operator 像已应用于函数本身一样工作,则最好使用函数引用,例如&amp;func&amp;f_ref 相同,但 &amp;f_ptr 是另一回事。

    【讨论】:

    • 这是一个实现错误吗? '因为这违背了我们直观的“打字”概念,对吧?我还看到像 void (*&amp;f)(void) 这样的东西作为函数的参数 - *&amp; 一起使用.. 怎么会?
    • 这不是错误,只是语言的定义方式。在表达式中基本上没有函数,只有函数指针;衰变负责使“明显”的语法工作(即您可以输入f(1),而不是更麻烦的(&amp;f)(1))。
    • @John:对比数组的处理方式;它们不能按值传递,因此在函数原型中,int x[](就此而言 (int x[10]) 等价于 int *x;因为按值接收 C 数组是不合法,他们让数组声明语法用作接收指针的语法糖。
    【解决方案2】:

    “为什么函数指针不需要解引用?”

    因为函数标识符本身实际上已经是指向函数的指针:

    4.3 函数到指针的转换
    §1 函数类型T 的左值可以转换为“指针”类型的右值到T。”结果是一个指向函数的指针。

    “为什么取消引用函数引用不会导致错误?”

    基本上,您可以将定义引用视为定义别名(替代名称)。即使在8.3.2 引用 标准中的部分地址创建对对象的引用,您也会发现:
    “引用可以被认为是对象的名称。 "

    所以当你定义一个引用时:

    void (& f_ref)(int) = func;
    

    它使您能够在几乎可以使用func 的任何地方使用f_ref,这就是为什么:

    f_ref(1);
    (*f_ref)(4);
    

    工作方式与直接使用func 完全相同:

    func(1);
    (*func)(4);
    

    【讨论】:

      【解决方案3】:

      here

      address-of 运算符的作用与您预期的一样,因为它指向一个函数但不能被赋值。函数在用作右值时会转换为函数指针,这意味着您可以多次取消引用函数指针并取回相同的函数指针。

      【讨论】:

        【解决方案4】:

        因为这里有其他人的好答案,所以没有答案解释为什么f_ptr = &amp;&amp;func; 不起作用。当您将 addressof 运算符 &amp; 应用于变量/函数时,您将获得其地址。地址本身是一个 r 值/一个临时变量。不能取临时地址。

        但是好像有类型错误。消息implicit conversion from void* 是非常特定于该代码的编译器。我猜你正在使用 GCC/Clang。 GCC/Clang 提供了获取标签地址的能力,例如&amp;&amp;label。结果值为void* 类型。其他编译器将输出类似cannot take address of temporaryinvalid 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;
        };
        

        但是谁会把所有东西都命名为一样的呢?

        【讨论】:

          猜你喜欢
          • 2016-09-19
          • 1970-01-01
          • 2021-09-08
          • 2017-05-30
          • 1970-01-01
          • 2017-07-13
          • 2011-06-17
          • 2012-07-11
          • 1970-01-01
          相关资源
          最近更新 更多