函数到函数指针"衰减"

use*_*986 14 c++

我们知道看起来像的参数void()将被重写为void(*)().这类似于阵列到指针衰变,其中int[]int*.在许多情况下,使用数组会将其衰减为指针.是否存在功能"衰减"的参数以外的情况?

C++标准规定:

§8.3.5/ 5

...在确定每个参数的类型之后,将"T的数组"或"返回的函数T"的任何参数分别调整为"指向T的指针"或"指向函数返回T的指针",...

由于下面的评论者似乎不相信我......我的编译器显示的是什么.

void handler(void func())
{
    func(42);
}

main.cpp: In function 'void handler(void (*)())':
main.cpp:5:12: error: too many arguments to function
     func(42);
        ^
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 9

有三种转换被认为是左值转换:左值到右值,数组到指针和函数到指针.您可以将此称为"衰变",因为这std::decay将对这些类型做什么,但标准只是将其称为函数到指针的转换[conv.func]:

函数类型的左值T可以转换为"指向T" 的类型的prvalue .结果是指向函数的指针.

如果你在询问函数到指针转换发生时的情况,它们基本上与其他两个左值转换发生时相同.如果我们按顺序完成标准,则以下是功能到指针转换发生的详尽列表:

使用函数作为操作数,[expr]/9:

每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,左值到右值(4.1),数组到指针(4.2)或函数到指针(4.3)标准转换是用于将表达式转换为prvalue.

使用函数作为varargs函数的参数,[expr.call]/7:

当给定参数没有参数时,参数的传递方式使得接收函数可以通过调用va_arg(18.10)...左值到右值(4.1),数组来获取参数的值.-pointer(4.2)和函数到指针(4.3)标准转换是在参数表达式上执行的.

你可以static_cast离开这个转换,[expr.static.cast]/7:

任何标准转换序列(第4章)的反转,不包含左值到右值(4.1),数组到指针(4.2),函数到指针(4.3),空指针(4.10),空成员指针(4.11) ),或布尔(4.12)转换,可以使用明确执行static_cast.

否则,传入的操作数将被转换,[expr.static.cast]/8:

左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)转换应用于操作数.

使用reinterpret_cast,[expr.reinterpret.cast]/1:

表达式reinterpret_cast<T>(v)的结果是将表达式转换v为type 的结果T.如果T是左值引用类型或函数类型的右值引用,则结果为左值; if T是对象类型的右值引用,结果是xvalue; 否则,结果是一个prvalue,并且对表达式执行lvalue-torvalue(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换v.

使用const_cast[expr.const.cast],与上面的措辞基本相同.使用条件运算符[expr.cond]:

在第二个和第三个操作数上执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换.

请注意,在上述所有情况中,它始终是所有左值变换.

在模板中也会发生函数到指针的转换.将函数作为非类型参数传递,[temp.arg.nontype] /5.4:

对于函数指针类型的非类型模板参数,应用函数到指针转换(4.3)

或者类型演绎,[temp.deduct.call]/2:

如果P不是引用类型:

  • - 如果A是数组类型,则使用由数组到指针标准转换(4.2)生成的指针类型来代替A类型推导; 除此以外,
  • - 如果A是函数类型,则使用函数到指针标准转换(4.3)产生的指针类型代替A类型推导; 除此以外,

或者转换函数模板扣除,用大致相同的措辞.

最后,当然,std::decay在[meta.trans.other]中定义的,强调我的:

我们Uremove_reference_t<T>.如果is_array<U>::value为true,则成员typedef类型应相等remove_extent_t<U>*.如果is_function<U>::value为true,则成员typedef类型应相等 add_pointer_t<U>.否则成员typedef类型等于 remove_cv_t<U>.[注意:当左值表达式用作右值时,此行为类似于左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)转换,但也从类类型中剥离cv -qualifiers,以便更接近地模拟按值参数传递. - 尾注]


axi*_*iac 6

当涉及到数据类型时,函数并不是 C 和 C++ 中的一等公民(问题是关于 C++ 的,但行为是从 C 继承的)。它们是代码,而不是数据,并且不能被复制、作为参数传递给函数或由函数返回(但所有这些都可能发生在指向函数的指针上。)

这就是为什么函数名被视为指向该函数的指针,而不是函数体本身。

使用函数(名称)而不是函数指针的可能性只是语言对程序员的礼貌,而不是“衰退”。

数组也是如此:它们不会被复制,不会作为函数参数传递,也不会由函数返回。而是使用它们的第一个元素的地址(复制、作为函数参数传递或由函数返回)。这就是为什么可以使用数组名称而不是其第一个元素的地址,并且这只是编写更少(并且更少混淆)代码的一种方法。

对于编译器来说,函数是一块不移动的内存块(包含在某个时间要执行的代码),并由其地址(即指向函数的指针)标识。数组也是一个不移动的数据块,由其地址(也是其第一个元素的地址)标识。再次强调,这是一个指针。

function较高级别(C、C++)中的和的概念array由编译器转换为较低级别(汇编程序、机器代码)可以理解的原始值(指针)。


And*_*Luo -3

是的,它们都是指针,第一个是函数指针,第二个是指向整数块的指针。* 看起来像一个点。