使用typedef来包装函数

时间:2012-11-12 18:13:22

标签: c++ function pointers wrapper typedef

我的一位老师使用此类型声明:

typedef void (*SortFunction)(int a[], int n);

创建一个可以保存指向函数的指针的类型 这可以用来稍后在程序中调用该函数。

我也知道要将函数作为参数传递 将函数名称括在括号中并包装函数 函数名后的括号中的参数也是如此

function someFunction( (anotherfunction)(type arg1, type arg2,...)){
  ...
} 

我想知道为什么你必须在这样的括号中包装一个函数?这是大多数c ++编译器的内置函数,还是我们程序员使用的技巧 为了在我们的代码中启用函数作为参数?还有,为什么“SortFunction” 在typedef语句中需要引用,为什么你用来使用SortFunction的变量只能保存函数而不是指向它?

4 个答案:

答案 0 :(得分:1)

函数参数没有什么特别之处。每当你声明一个函数指针(作为局部变量,全局变量,类成员变量,函数参数,typedef等)时,它总是被声明为:

return_type (*var_name)(T1 param1, T2 param2, /* etc. */ );
//           ^
//           |
// This * is very important!

其中var_name是函数指针变量的名称。围绕*var_name需要括号的原因是由于运算符优先级:没有括号,*(表示某些东西是指针)与函数的返回类型匹配,而是你得到的东西像返回类型int*(指向int)而不是普通int

您不能将函数作为参数传递,因为函数不是C和C ++中的第一类对象。传递函数的唯一方法是传递一个指向函数的指针。

答案 1 :(得分:1)

“我也知道要将函数作为参数传递,你必须将函数名称括在括号中......”你“错误地”知道了。

为了将函数指针作为参数传递,您不必将名称包装在括号中。例如,这将完美无缺

void foo(int i) {
} 

void bar(void f(int)) {
  f(5);
}

int main() {
  bar();
}

在上面的示例中,函数bar接收指向函数foo的指针作为参数,并通过该指针调用foo,将5作为参数传递。如您所见,参数声明中的函数名f而不是包装在括号中。

在这种情况下,参数f的类型实际上是函数的指针,即使它没有显式声明为指针。在函数参数声明中使用函数类型时,编译器会自动用函数指针类型“替换”它。

如果要显式使用函数指针类型,则必须将bar声明为

void bar(void (*f)(int)) {
  f(5);
}

在这种情况下,(*f)中的括号是必要的,以确保*绑定到f而不是void。如果没有括号,void *f(int)声明将代表“函数返回void *”而不是所需的“返回void函数的指针”。

答案 2 :(得分:0)

这是语法问题。您的第一个typedef定义了一个类型,该类型是一个接收intint向量并且不返回任何内容(void)的函数。

类型SortFunction的变量在概念上将与任何其他变量一样,尽管它指向某个函数。优点是您可以更改它指向的功能和/或动态调用该功能。

答案 3 :(得分:0)

  

我想知道为什么你必须在这样的括号中包装一个函数?

因为必须有某种方法来识别指向编译器(或者更确切地说是解析器)的函数指针,并且这种方式看起来和任何方式一样好。在C ++ 11中,您可以使用它代替:std::function<void(std::array<int>&)>

  

这是大多数c ++编译器的内置函数,还是我们程序员使用的一个技巧,以便在我们的代码中启用函数作为参数?

函数指针需要一些额外的魔力,如果没有编译器支持,它们将非常非常不方便使用。我也有理由相信,编程本质上几乎所有的程序员技巧都是编译器的最终功能!

  

另外,为什么需要引用typedef语句中的“SortFunction”,为什么用于利用SortFunction的变量只能保存函数而不是指向它?

嗯。不完全确定你的意思。你的意思是“为什么这需要一个typedef ...为什么我不能在函数参数中写出整个函数指针原型”?你可以:

void foo(void(*funcptr)()) {}

如果你的意思是“为什么函数指针必须指向一个函数而不是代码内联”那么你需要C ++ 11和lambdas:

#include <iostream>
#include <functional>

void foo(std::function<void(void)> bar) { bar(); }

int main(int argc, char* argv[])
{
    foo([]() { std::cout << "hi!" << std::endl; });
}

(同样,lambdas需要特殊的语法,[](){},只是为了告诉解析器发生了什么)