3.5.2 函数引用
引用也可以用来指代一个函数,这种引用称为函数引用。例如:
int add(int a, int b) { return a + b;}
auto& add_ref = add; // add_ref 是 add 函数的引用
int result = add_ref(1, 2); // 调用 add 函数这里的 add_ref 是 add 函数的引用,可以像函数一样调用。这种引用称为函数的引用。
函数引用也可以作为函数的参数,例如:
int apply(auto& func, int a, int b) { return func(a, b);}
int result = apply(add, 1, 2);在这里,apply 函数接受一个函数引用作为参数,然后调用这个函数。
函数类型与函数引用类型
Section titled “函数类型与函数引用类型”读者可以发现,在上面的例子中,apply 函数中的参数 auto& func 也能绑定到对象。此时:
int a = 1;int result = apply(a, 2, 3); // 错误,a 不是函数这样就会产生错误,因为 a 不是函数。但是这个错误会出现在 apply 函数里面,在调用方并不会产生提示。
此时,我们就会希望通过类型来限制 func 只能绑定到函数。这就需要使用函数类型,以及函数引用类型。
函数类型的形式是
return_type (parameter_type1, parameter_type2, ...)这里的 return_type 是函数的返回值类型,parameter_type1, parameter_type2, ... 是函数的参数类型。例如:
using binary_int_func = int(int, int);这样,binary_int_func 就是一个函数类型,它接受两个 int 类型的参数,返回一个 int 类型的值。
在我们声明了 binary_int_func 之后,就可以使用这个类型来限制 func 的类型:
// 通过在 binary_int_func 后面加上 & 来组成一个函数引用类型int apply(binary_int_func& func, int a, int b) { return func(a, b);}
int a = 1;apply(a, 2, 3); // 错误,a 不是函数
float add(float a, float b) { return a + b;}apply(add, 2, 3); // 错误,add 类型不匹配这样,在调用 apply 函数时,就会提示无法用 a 初始化 apply 的第一个参数。这在 apply 函数的实现比较复杂的时候能够有效的提升分析错误的效率。
在返回值中使用函数引用
Section titled “在返回值中使用函数引用”函数引用也可以作为函数的返回值,例如:
using binary_int_func = int(int, int);
binary_int_func& get_add() { return add;}
auto& add_ref = get_add(); // add_ref 是 add 函数的引用int result = add_ref(1, 2); // 调用 add 函数在这里,get_add 函数返回了 add 函数的引用,然后我们可以通过 add_ref 来调用 add 函数。
当然,get_add 可以调用再紧跟调用,不需要额外的变量:
int result = get_add()(1, 2); // 调用 add 函数结合之前提到switch 语句的例子,我们可以把 get_add 函数进一步扩展:
using binary_int_func = int(int, int);
int add(int a, int b) { return a + b;}
int sub(int a, int b) { return a - b;}
int mul(int a, int b) { return a * b;}
int div(int a, int b) { return a / b;}
int no_such_operator(int a, int b) { return 0;}
binary_int_func& get_func(char op) { switch (op) { case '+': return add; case '-': return sub; case '*': return mul; case '/': return div; default: return no_such_operator; }}这样,我们就可以通过 get_func 来获取不同的函数引用,然后调用这些函数。例如:
int result = get_func('+')(1, 2); // 调用 add 函数函数右值引用
Section titled “函数右值引用”函数引用也可以是右值引用,例如:
using binary_int_func = int(int, int);
int add(int a, int b) { return a + b;}
binary_int_func&& get_add() { return add;}你可能会奇怪,这里的 add 在前面的例子里,似乎是绑定到左值引用的,这里为什么能绑定到右值引用?这是 C++ 为了方便使用所做的规定,右值引用和左值引用都可以绑定到函数,并得到一个有效的函数引用。
函数不是对象,也没有赋值的事情,不需要区分左值和右值。这里不区分左值和右值的设计可以让一些代码的设计更为简洁,在后面的章节中我们会看到相关例子。