同样,C ++函数指针。关于语法的困惑

射线

此页面上,我找到了一个很好的C ++函数指针示例(以及函子,但是这个问题与函子无关)。以下是该页面的一些复制内容。

#include <iostream>

double add(double left, double right) {
  return left + right;
}

double multiply(double left, double right) {
  return left * right;
}

double binary_op(double left, double right, double (*f)(double, double)) {
  return (*f)(left, right);
}

int main( ) {
  double a = 5.0;
  double b = 10.0;

  std::cout << "Add: " << binary_op(a, b, add) << std::endl;
  std::cout << "Multiply: " << binary_op(a, b, multiply) << std::endl;

  return 0;
}

我大致理解了代码,但是有些事情我总是感到困惑。函数binary_op()接受一个函数指针*f,但是当使用它时(例如在第19行)binary_op(a, b, add)add传递函数符号,而不是传递给它的指针&add现在您可能会说这是因为符号add 一个指针。它是与功能相对应的代码位的地址add()很好,但是这里似乎仍然存在类型差异。该函数binary_op()采用*f,这意味着f它是指向某物的指针。我传入add,它本身就是代码的指针。(对吗?)然后f为分配了的值add,这使得f指向代码的指针,这意味着该f函数就像add,这意味着f应该调用like f(left, right)add应该如何调用,但是在第12行,它被称为like (*f)(left, right),这对我来说似乎不对,因为它就像写作(*add)(left, right),而*add不是功能,它的代码的第一个字符add点。(对?)

我知道用binary_op()以下内容替换的原始定义也可以。

double binary_op(double left, double right, double f(double, double)) {
  return f(left, right);
}

实际上,这对我来说更有意义,但是如我上面所解释的,原始语法没有意义。

那么,为什么使用语法(*f)而不是仅仅语法正确f如果符号func本身就是指针,那么“函数指针”或“函数指针”究竟是什么意思?就目前的原始代码而言,当我们编写代码时double (*f)(double, double),那是什么一回事f指向指针的指针(因为(*f)本身就是指向一点代码的指针)?该符号是否与add事物(*f)相同或相同f

现在,如果所有这些的答案是“是的,C ++语法很奇怪,只需记住函数指针语法,不要质疑它”。,那么我会很不情愿地接受它,但是我真的很想对我在这里想的错做一个正确的解释。

我已经阅读了这个问题,我想我理解这一点,但是并没有发现它有助于解决我的困惑。我也阅读了这个问题,它也没有帮助,因为它不能直接解决我的类型差异问题。我可以继续阅读互联网上的信息之海,以找到答案,但是,嘿,这就是Stack Overflow的目的吗?

埃雷里卡

就目前的原始代码而言,当我们编写代码时double (*f)(double, double),那是什么一回事f

的类型为fdouble (*)(double, double)即它是类型函数的指针double(double,double)

因为(*f)它本身就是一个指针

它不是。

问:通过指针间接访问(例如in中*f)会得到什么?答:您会得到一个左值参考。例如,给定的对象的指针int* ptr,该表达式的类型*ptrint&即左值参考int

对于函数指针也是如此:当您通过函数指针间接访问时,您将获得指向所指向函数的左值引用。在情况下*f,类型是double (&)(double, double)对类型函数的引用double(double,double)

该符号是否与add事物(*f)相同或相同f

不合格的id表达式add*f它是一个左值是一样的事情

标准草稿[expr.prim.id.unqual]

...如果实体是函数,则表达式为左值...


函数符号add被传入,而不是人们认为它的指针&add现在您可能会说这是因为符号add是一个指针。

不,那不是原因。

add不是指针。它是一个左值。但是函数类型的左值会隐式转换为指针(这称为衰减):

标准草稿[转换功能]

函数类型T的左值可以转换为“指向T的指针”的前值。结果是指向该函数的指针。

因此,以下在语义上是等效的:

binary_op(a, b,  add); // implicit function-to-pointer conversion
binary_op(a, b, &add); // explicit use of addressof operator

那么,为什么使用语法(*f)而不是仅仅语法正确f

事实证明,调用函数左值与调用函数指针具有相同的语法:

标准草稿[expr.call]

函数调用是一个后缀表达式,后跟括号,其中包含可能是空的,逗号分隔的初始化程序子句列表,这些子句构成了函数的参数。后缀表达式应具有函数类型或函数指针类型。对于非成员函数或静态成员函数的调用,后缀表达式应为引用函数左值(在这种情况下,函数到指针的标准转换([conv.func])将被禁止(在后缀表达式上),或者具有函数指针类型

这些都是相同的函数调用:

add(parameter_list);    // lvalue
(*f)(parameter_list);   // lvalue

(&add)(parameter_list); // pointer
f(parameter_list);      // pointer

PS这两个声明是等效的:

double binary_op(double, double, double (*)(double, double))
double binary_op(double, double, double    (double, double))

这是由于以下规则,它与隐式衰减到函数指针相辅相成:

标准草案[dcl.fct]

函数的类型使用以下规则确定。每个参数的类型(包括功能参数包)由其自己的decl-specifier-seq和声明符确定。在确定每个参数的类型之后,将类型为“ T的数组”或函数类型为T的任何参数调整为“指向T的指针” ...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章