有三种转换被视为左值转换:左值到右值、数组到指针和函数到指针。你可以称之为“衰变”,因为这就是std::decay
将对这些类型进行处理,但标准只是将其称为函数到指针的转换 [conv.func]:
函数类型的左值T
可以转换为“指向的指针”类型的纯右值T
”。结果是指向该函数的指针。
如果您询问发生函数到指针转换时的情况,它们基本上与发生其他两个左值转换时相同。如果我们只是按顺序浏览标准,以下是发生函数到指针转换的情况的详尽列表:
使用函数作为操作数,[expr]/9:
每当左值表达式作为需要该操作数纯右值的运算符的操作数出现时,
应用左值到右值 (4.1)、数组到指针 (4.2) 或函数到指针 (4.3) 标准转换
将表达式转换为纯右值。
使用函数作为可变参数函数的参数,[expr.call]/7:
当给定参数没有参数时,参数的传递方式使得接收函数可以通过调用来获取参数的值va_arg
(18.10)... 左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换是对参数表达式执行的。
You can static_cast
去掉这个转换,[expr.static.cast]/7:
不包含左值到右值 (4.1)、数组到- 的任何标准转换序列(第 4 条)的逆
指针 (4.2)、函数到指针 (4.3)、空指针 (4.10)、空成员指针 (4.11) 或布尔值 (4.12)
转换,可以使用显式执行static_cast
.
尽管如此,您传入的操作数将被转换,[expr.static.cast]/8:
左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 转换应用于
操作数。
Using reinterpret_cast
, [expr.reinterpret.cast]/1:
表达式的结果reinterpret_cast<T>(v)
是表达式转换的结果v
输入T
. If T
是左值引用类型或函数类型的右值引用,结果是左值;如果T
是一个
对象类型的右值引用,结果是 xvalue;否则,结果是右值和左值-前值
(4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换是在
表达v
.
Using const_cast
,[expr.const.cast],与上面的措辞基本相同。使用条件运算符 [expr.cond]:
执行左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 标准转换
在第二个和第三个操作数上。
请注意,在上述所有情况下,它总是all左值变换。
在模板中也会发生函数到指针的转换。将函数作为非类型参数传递,[temp.arg.nontype]/5.4:
对于非类型模板参数类型指针到函数,函数到指针的转换(4.3)
被申请;被应用
或者输入推导,[temp.deduct.call]/2:
If P
不是引用类型:
- — If
A
是数组类型,则数组到指针标准转换 (4.2) 生成的指针类型为
用于代替A
用于类型推导;否则,
- — If
A
是函数类型,由函数到指针标准转换产生的指针类型(4.3)
用于代替A
用于类型推导;否则,
或者转换函数模板推导,写法大致相同。
最后,当然,std::decay
本身,在 [meta.trans.other] 中定义,强调我的:
Let U
be remove_reference_t<T>
. If is_array<U>::value
是真的,则
成员 typedef 类型应等于remove_extent_t<U>*
. If is_function<U>::value
为 true 时,成员 typedef 类型应等于add_pointer_t<U>
。否则成员 typedef 类型等于remove_cv_t<U>
。 [ 注意:此行为类似于
当左值表达式用作右值时应用左值到右值 (4.1)、数组到指针 (4.2) 和函数到指针 (4.3) 转换,但也会剥离cv-来自类类型的限定符,以便更紧密地按值建模
论证传递。 ——尾注]