有没有这两个高阶函数定义有何区别? [英] Are there any differences between these two higher-order function definitions?

查看:112
本文介绍了有没有这两个高阶函数定义有何区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有中间主4陈述什么不同吗?
我觉得只有apply2(安培; FUNC)是有道理的。然而,所有4返回相同的值。

  INT FUNC(无效)
{
    返回1;
}INT apply1(INT F1(无效))
{
    返回F1();
}INT apply2(INT(* F1)(无效))
{
    返回F1();
}诠释的main()
{
    apply1(FUNC);
    apply1(安培; FUNC);
    apply2(FUNC);
    apply2(安培; FUNC);    返回0;
}


解决方案

首先,函数指针是很难的。认为你可以将一个函数作为参数传递给另一个函数需要一些令人费解的类似理解递归。起初,你不会得到它,但后来突然它就像了解在你的大脑开方便之门,你是开明的。

但是,你仍然必须知道传递函数为C和C ++参数的规则。在这些语言中,函数不是一等公民,所以有很多你可以与他们做什么限制。

语法

函数指针语法是有点难看。基本的解剖 [返回类型(* [名])([参数列表])。周围的括号 *名称必要一个函数指针和一个函数返回一个指针之间的歧义:

  //没有函数指针:*不分组,以函数名
INT X(); //函数返回一个int
INT * X(); //函数返回一个int *
INT * X(); //也返回一个int *的函数,空间并不重要//函数指针:*分组,以函数名
INT(* X)(); //指针,返回一个int的函数
为int *(* X)(); //指向返回一个int *的函数

衰减

在传递作为参数的方面,函数的行为大致相同的阵列。当传递,他们变成一个指针。比较:

 无效美孚(INT条[4]); //等同于:无效美孚(INT *巴)
空栏(INT巴兹()); //等同于:无效酒吧(INT(*巴兹)())

这很简单,因为功能和数组都是不可转让及不可复制:

  INT富[4];
INT酒吧[4] = foo的; //无效INT富();
INT栏()= foo的; //无效

因此​​,只有这样才能将它们作为函数的参数是不是通过拷贝它们自己的地址。 (这是有争议的数组,但这是它是如何工作的。)当作为参数传递,这些价值转化为指针的事实被称为腐烂。

这两种原型是兼容(即,它们指的是相同的功能,而不是不同的重载),因此,这两者之间没有差别:

  INT富(空栏());
INT富(无效(*巴)());

视觉效果之外,还有绝对是这两个声明之间没有什么区别。这两个函数接受一个函数的指针的,不管它看起来喜欢还是不喜欢,因为的衰减的的。不过,因为衰退通常被认为是一个讨厌的和令人困惑的事情,大多数开发商将preFER明确地要求一个函数指针(和很多开发商甚至不知道函数类型可以衰减)。

隐式转换

现在,有关传递函数作为参数。这一次仅仅是腐烂的后果:函数必须隐式转换为自己的函数指针类型。这意味着,你可以在这里传递一个函数指针预期的函数,编译器会得到它的地址给你。为了这个目的,这些是,再次,相同的

  INT富();
INT(*巴)()= foo的; //编译器隐式地分配foo的地址吧
INT(*巴兹)()=&安培; foo的; //你明确指定foo的地址BAZ

联合这两个解释,你会意识到,你的四个功能调用都是一样的。 apply1 apply2 均接受该相同类型参数( INT(*)(无效) ),即使这不是很明显的 apply1 ;当你调用与的功能FUNC 而不是&放大器; FUNC ,编译器隐含需要的地址给你,使它等同于&放大器; FUNC。


以下是该问题的范围,但它阐述了previous一部分,我认为这是一种整齐。

函数引用[仅限于C ++]

有一个鲜为人知的事实,但也有可能通过的引用的到阵列和功能:在这种情况下,没有腐烂情况。像这样的:

 无效美孚(INT(安培巴)[4]); //不等同于无效美孚(INT *巴)
无效酒吧(中间体(安培;巴兹)()); //不等同于无效栏(INT(*巴兹)())

在这种情况下,你是不是允许使用地址的运营商,因为指针类型和引用类型之间不存在隐式转换。击败衰退通常被视为一件好事,因为衰退往往是混乱的。

  INT巴兹();
巴(巴兹); //有效
酒吧(安培;巴兹); //无效

函数引用遵循相同的规则,正常引用:他们只能在定义时被分配,而不能为空

的typedef

您可以函数指针的使用较少的丑的typedef

 的typedef INT(* X)();
点¯xFUNC; // func为指针,以返回一个int的函数

事情变得更加有趣,如果你拿出(*)部分:

 的typedef INT X();
X * FUNC; // func为一个函数指针
X'放大器; FUNC; // func为一个函数引用[仅限于C ++]
点¯xFUNC; // func为一个函数声明(!!)

在后一种情况下, X FUNC; 等同于 INT FUNC()的声明说; 。在家里,除非你想混淆的地狱大家不这样做。

decltype 有差别[仅限于C ++]

函数和函数指针之间的另一个有趣的不同产生的使用 decltype 的。 decltype 收益的前presson的类型。对于这种结构,有函数之间的差异&放大器;功能

  INT巴();
decltype(巴); //类型是int()
decltype(安培巴); //类型是int(*)()

如果你想传递的类型作为模板参数这种差异是非常重要的,比如说,到的std ::的unique_ptr

 的std ::的unique_ptr<无效,decltype(免费)>富; //无效
的std ::的unique_ptr<无效,decltype(安培;免费)GT;富; //有效

首先是无效的,因为它会试图创建的unique_ptr 函数,如的一个实例字段。

Are there any differences among 4 statements in main? I feel only apply2(&func) makes sense. However, all 4 return the same value.

int func(void) 
{
    return 1;
}

int apply1( int f1(void) )
{
    return f1();
}

int apply2( int (*f1) (void) ) 
{
    return f1();
}

int main() 
{
    apply1(func); 
    apply1(&func);
    apply2(func);
    apply2(&func);

    return 0;
}

解决方案

First off, function pointers are hard. Thinking that you can pass a function as a parameter to another function requires some mind-bending similar to understanding recursion. You won't get it at first, but then all of a sudden it's like the floodgates of understanding open in your brain and you're enlightened.

But then, you still have to know the rules of passing functions as parameters in C and C++. In these languages, functions are not first-class citizens, so there are a lot of restrictions on what you can do with them.

Syntax

The function pointer syntax is a little ugly. The basic anatomy is [return type] (*[name])([argument list]). The parentheses around *name are necessary to disambiguate between a function pointer and a function returning a pointer:

// not function pointers: * not grouped to function name
int x(); // function that returns an int
int* x(); // function that returns an int*
int *x(); // also a function that returns an int*, spaces don't matter

// function pointers: * grouped to function name
int (*x)(); // pointer to a function that returns an int
int* (*x)(); // pointer to a function that returns an int*

Decay

In terms of passing as parameters, functions behave about the same as arrays. When passed, they change into a pointer. Compare:

void Foo(int bar[4]); // equivalent to: void Foo(int* bar)
void Bar(int baz()); // equivalent to: void Bar(int (*baz)())

This is simply because functions and arrays are non-assignable and non-copyable:

int foo[4];
int bar[4] = foo; // invalid

int foo();
int bar() = foo; // invalid

Therefore, the only way to pass them as function parameters is to pass their address instead of copying them. (This is disputable for arrays, but that's how it works.) The fact that these "values" are transformed into pointers when passed as parameters is called "decay".

These two prototypes are compatible (that is, they refer to the same function, not different overloads), and therefore, there is no difference between the two:

int foo(void bar());
int foo(void (*bar)());

Visuals aside, there is absolutely no difference between those two declarations. Both functions accept a function pointer, whether it looks like it or not, because of decay. Though, since decay is often considered a nasty and confusing thing, most developers will prefer to explicitly ask for a function pointer (and a lot of developers don't even know function types can decay).

Implicit Conversions

Now, about passing functions as parameters. This one is simply a consequence of decay: functions have to be implicitly convertible to their function pointer type. This means that you can pass a function where a function pointer is expected, and the compiler will get its address for you. For this purpose, these are, once again, the same:

int foo();
int (*bar)() = foo; // the compiler implicitly assigns the address of foo to bar
int (*baz)() = &foo; // you explicitly assign the address of foo to baz

Combine those two explanations, and you'll realize that your four function calls are all the same. apply1 and apply2 both accept the same type of parameter (int (*)(void)), even if it's not obvious for apply1; and when you call the functions with func instead of &func, the compiler implicitly takes the address for you and makes it equivalent to &func.


The following is outside the scope of the question, but it elaborates on the previous part, and I think it's kind of neat.

Function References [C++ only]

It is a little-known fact, but it is also possible to pass references to arrays and functions: in this case, no decay happens. Like this:

void Foo(int (&bar)[4]); // NOT equivalent to void Foo(int* bar)
void Bar(int (&baz)()); // NOT equivalent to void Bar(int (*baz)())

In this scenario, you are not allowed to use the address-of operator, because there is no implicit conversion between pointer types and reference types. Defeating decay is generally seen as a good thing, as decay is often confusing.

int baz();
Bar(baz); // valid
Bar(&baz); // INVALID

Function references obey the same rules as normal references: they can be assigned only at definition time, and cannot be null.

Typedefs

You can make function pointers less ugly using typedef.

typedef int (*X)();
X func; // func is a pointer to a function that returns an int

Things get more interesting if you take out the (*) part:

typedef int X();
X* func; // func is a function pointer
X& func; // func is a function reference [C++ only]
X func; // func is a function declaration (!!)

In the latter case, X func; is equivalent to a declaration saying int func();. Don't do this at home, unless you want to confuse the hell out of everyone.

decltype makes a difference [C++ only]

Another interesting difference between functions and function pointers arises with the use of decltype. decltype "returns" the type of an expresson. For this construct, there is a difference between function and &function:

int bar();
decltype(bar); // type is int ()
decltype(&bar); // type is int (*)()

This difference is especially important if you want to pass the type as a template parameter, say, to std::unique_ptr.

std::unique_ptr<void, decltype(free)> foo; // INVALID
std::unique_ptr<void, decltype(&free)> foo; // valid

The first is invalid because it would attempt to create a function as an instance field of unique_ptr.

这篇关于有没有这两个高阶函数定义有何区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆