[英]Function-to-function-pointer "decay"
As we know a parameter that looks like void()
will be rewritten as void(*)()
.我们知道一个看起来像
void()
的参数将被重写为void(*)()
。 This is similar to array-to-pointer decay where int[]
becomes int*
.这类似于数组到指针的衰减,其中
int[]
变为int*
。 There are many cases where using an array will decay it to a pointer.在很多情况下,使用数组会将其衰减为指针。 Are there cases other than parameters where functions "decay"?
除了参数之外,还有没有函数“衰减”的情况?
The C++ standard states: C++ 标准规定:
§8.3.5/5 §8.3.5/5
... After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively...
...确定每个参数的类型后,将“T的数组”或“返回T的函数”类型的任何参数分别调整为“指向T”或“指向function返回T的指针”,...
Since the commenter below doesn't seem to believe me..here's what my compiler shows.由于下面的评论者似乎不相信我..这就是我的编译器显示的内容。
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);
^
There are three conversions that are considered lvalue transformations: lvalue-to-rvalue, array-to-pointer, and function-to-pointer.存在三种被认为是左值转换的转换:左值到右值、数组到指针和函数到指针。 You can call this "decay" since that's what
std::decay
will do to these types, but the standard just calls this a function-to-pointer conversion [conv.func]:你可以称之为“衰减”,因为这就是
std::decay
会对这些类型做的事情,但标准只是将其称为函数到指针的转换 [conv.func]:
An lvalue of function type
T
can be converted to a prvalue of type “pointer toT
.”函数类型
T
的左值可以转换为“指向T
指针”类型的右值。 The result is a pointer to the function.结果是一个指向函数的指针。
If you're asking for what the cases are for when a function-to-pointer conversion happens, they are basically the same as when the other two lvalue transformations would happen.如果您询问函数到指针转换发生时的情况,它们与其他两个左值转换发生时的情况基本相同。 If we just go through the standard in order, the following is an exhaustive list of cases where function-to-pointer conversion happens:
如果我们只是按顺序浏览标准,以下是发生函数到指针转换的情况的详尽列表:
Using a function as an operand, [expr]/9:使用函数作为操作数,[expr]/9:
Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue (4.1), array-to-pointer (4.2), or function-to-pointer (4.3) standard conversions are applied to convert the expression to a prvalue.
每当泛左值表达式作为期望该操作数的纯右值的运算符的操作数出现时,左值到右值 (4.1)、数组到指针 (4.2) 或函数到指针 (4.3) 的标准转换是应用于将表达式转换为纯右值。
Using a function as an argument to a varargs function, [expr.call]/7:使用函数作为可变参数函数的参数,[expr.call]/7:
When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking
va_arg
(18.10)... The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the argument expression.当给定参数没有参数时,参数以这样一种方式传递,即接收函数可以通过调用
va_arg
(18.10)... 左值到右值 (4.1),数组-对参数表达式执行到指针 (4.2) 和函数到指针 (4.3) 标准转换。
You can static_cast
away this conversion, [expr.static.cast]/7:你可以
static_cast
去掉这个转换,[expr.static.cast]/7:
The inverse of any standard conversion sequence (Clause 4) not containing an lvalue-to-rvalue (4.1), arrayto- pointer (4.2), function-to-pointer (4.3), null pointer (4.10), null member pointer (4.11), or boolean (4.12) conversion, can be performed explicitly using
static_cast
.不包含左值到右值 (4.1)、数组到指针 (4.2)、函数到指针 (4.3)、空指针 (4.10)、空成员指针 (4.11) 的任何标准转换序列(第 4 条)的反转) 或布尔 (4.12) 转换,可以使用
static_cast
显式执行。
Though otherwise, the operand you pass in will get converted, [expr.static.cast]/8:否则,您传入的操作数将被转换,[expr.static.cast]/8:
The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) conversions are applied to the operand.
左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 的转换应用于操作数。
Using reinterpret_cast
, [expr.reinterpret.cast]/1:使用
reinterpret_cast
, [expr.reinterpret.cast]/1:
The result of the expression
reinterpret_cast<T>(v)
is the result of converting the expressionv
to typeT
.表达式
reinterpret_cast<T>(v)
的结果是将表达式v
转换为类型T
。 IfT
is an lvalue reference type or an rvalue reference to function type, the result is an lvalue;如果
T
是左值引用类型或函数类型的右值引用,则结果是左值; ifT
is an rvalue reference to object type, the result is an xvalue;如果
T
是对对象类型的右值引用,则结果是一个 xvalue; otherwise, the result is a prvalue and the lvalue-torvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the expressionv
.否则,结果是一个纯右值,并对表达式
v
执行左值-torvalue (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换。
Using const_cast
, [expr.const.cast], with basically identical wording to the above.使用
const_cast
, [expr.const.cast],与上述的措辞基本相同。 Using the conditional operator, [expr.cond]:使用条件运算符,[expr.cond]:
Lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the second and third operands.
左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换在第二个和第三个操作数上执行。
Notice in all of the above cases, it's always all of the lvalue transformations.请注意,在上述所有情况下,始终是所有左值转换。
Function-to-pointer conversions also occur when in templates.在模板中也会发生函数到指针的转换。 Passing a function as a non-type parameter, [temp.arg.nontype]/5.4:
将函数作为非类型参数传递,[temp.arg.nontype]/5.4:
For a non-type template-parameter of type pointer to function, the function-to-pointer conversion (4.3) is applied
对于指向函数的类型指针的非类型模板参数,应用函数到指针转换(4.3)
Or type deduction, [temp.deduct.call]/2:或者输入推导,[temp.deduct.call]/2:
If
P
is not a reference type:如果
P
不是引用类型:
- — If
A
is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place ofA
for type deduction;— 如果
A
是数组类型,则使用数组到指针标准转换(4.2)产生的指针类型代替A
进行类型推导; otherwise,除此以外,
- — If
A
is a function type, the pointer type produced by the function-to-pointer standard conversion (4.3) is used in place ofA
for type deduction;— 如果
A
是函数类型,则使用函数到指针标准转换(4.3)产生的指针类型代替A
进行类型推导; otherwise,除此以外,
Or conversion function template deduction, with roughly the same wording.或者转换函数模板推导,写法大致相同。
And lastly, of course, std::decay
itself, defined in [meta.trans.other], emphasis mine:最后,当然,
std::decay
本身,在 [meta.trans.other] 中定义,强调我的:
Let
U
beremove_reference_t<T>
.让
U
成为remove_reference_t<T>
。 Ifis_array<U>::value
is true, the member typedef type shall equalremove_extent_t<U>*
.如果
is_array<U>::value
为真,则成员 typedef 类型应等于remove_extent_t<U>*
。 Ifis_function<U>::value
is true, the member typedef type shall equaladd_pointer_t<U>
.如果
is_function<U>::value
为真,则成员 typedef 类型应等于add_pointer_t<U>
。 Otherwise the member typedef type equalsremove_cv_t<U>
.否则,成员 typedef 类型等于
remove_cv_t<U>
。 [ Note: This behavior is similar to the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) conversions applied when an lvalue expression is used as an rvalue, but also strips cv -qualifiers from class types in order to more closely model by-value argument passing.[ 注意:此行为类似于左值表达式用作右值时应用的左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 的转换,但也从类类型中去除cv 限定符,以便更接近地模拟按值参数传递。 —end note ]
——尾注]
When it's about data types, functions are not first class citizens in C and C++ (the question is about C++ but the behaviour is inherited from C).当涉及数据类型时,函数不是 C 和 C++ 中的一等公民(问题是关于 C++,但行为是从 C 继承的)。 They are code, not data and they cannot be copied, passed as arguments to functions or returned by functions (but all these can happen to pointers to functions.)
它们是代码,而不是数据,它们不能被复制、作为参数传递给函数或由函数返回(但所有这些都可能发生在指向函数的指针上。)
This is why a function name is treated like a pointer to that function and not like the function body itself.这就是为什么函数名称被视为指向该函数的指针而不是函数体本身的原因。
The possibility to use a function (name) instead of a pointer to the function is just a courtesy the language makes to the programmer, and not a "decay".使用函数(名称)而不是函数指针的可能性只是语言对程序员的一种礼貌,而不是“衰败”。
The same for arrays: they are not copied, not passed as function arguments and not returned by functions.数组也是一样:它们不会被复制,不会作为函数参数传递,也不会由函数返回。 The address of their first element is used instead (copied, passed as function argument or returned by functions).
而是使用它们的第一个元素的地址(复制、作为函数参数传递或由函数返回)。 This is why the array name can be used instead of the address of its first element and again, this is just a way to write less (and less obfuscated) code.
这就是为什么可以使用数组名称而不是其第一个元素的地址,这只是一种编写更少(和更少混淆)代码的方法。
For the compiler, a function is a block of memory (that contains code to be executed at some time) that does not move and is identified by its address, ie the pointer to the function.对于编译器来说,函数是一块不会移动的内存块(其中包含要在某个时间执行的代码),它由其地址标识,即指向函数的指针。 An array is also a block of data that does not move and is identified by its address (which is also the address of its first element).
数组也是一个不会移动的数据块,由它的地址(也是它的第一个元素的地址)标识。 Again, this is a pointer.
再次,这是一个指针。
The concepts of function
and array
at higher levels (C, C++) are translated by the compiler to primitive values (pointers) that are understood by the lower levels (assembler, machine code).较高级别(C、C++)的
function
和array
概念由编译器转换为较低级别(汇编程序、机器代码)理解的原始值(指针)。
Another obvious similarity between arrays and functions would be the following:数组和函数之间的另一个明显相似之处如下:
void bar(string message)
{
cout << message << endl;
}
void main()
{
int myArray[10];
int* p = myArray; //array to pointer to array
void (*f)(string);
f = bar; //function to function pointer decay
}
yes they are both pointers, first is a function pointer, second is a pointer to a block of ints.是的,它们都是指针,第一个是函数指针,第二个是指向 int 块的指针。 * looks like a point.
* 看起来像一个点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.