16 c++ pointers language-lawyer c++11
这是我前一个问题的切线跟进.匹配bool vs const void*overload的函数的地址.回答者解释说:
[C++ 11]标准没有定义从"指向函数的指针"到"指向"的任何标准转换
void.没有东西可以提供引用,但我能做的最接近的是C++ 11 4.10/2 [conv.ptr]:
类型为"指向cv的 指针"的prvalue
T,其中T是对象类型,可以转换为类型为"指向cv的 指针"的prvaluevoid.一个"指针转换的结果CVT"发送给"指针CVvoid"指向其中类型的对象的存储位置的起始T驻留,仿佛对象是类型T的最派生对象(1.8)(即,而不是基类子对象).空指针值将转换为目标类型的空指针值.(强调我的)
假设func是声明void func();,如果你进行C风格的演员表,即(void*) func演员表会成功.static_cast<void*>(func)但是无效,但reinterpret_cast<void*>(func)会成功.但是,您无法将后续转换的指针转换回其原始类型.例如,
精细:
int main() {
int* i;
void* s = static_cast<void*>(i);
i = static_cast<int*>(s);
s = reinterpret_cast<void*>(i);
i = reinterpret_cast<int*>(s);
}
Run Code Online (Sandbox Code Playgroud)
不好:
void func() { }
int main() {
void* s = reinterpret_cast<void*>(func);
reinterpret_cast<decltype(func)>(s);
}
Run Code Online (Sandbox Code Playgroud)
N3337开始说,
[expr.reinterpret.cast]
表达式
reinterpret_cast<T>(v)的结果是将表达式转换v为type 的结果T.如果T是左值引用类型或函数类型的右值引用,则结果为左值; ifT是对象类型的右值引用,结果是xvalue; 否则,结果是一个prvalue,并且对表达式v执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换.可以执行的转换明确使用reinterpret_cast如下所列.无法使用明确执行其他转换reinterpret_cast.
我粗犷的语言,我认为是关键在这里.最后一部分似乎暗示如果没有列出转换,那就是非法的.简而言之,允许的转换是:
X类型的T1"可被明确地转换成不同类型的prvalue"指向类型Y的成员T2"如果T1和T2都为函数类型或两者的对象类型.T1可以将类型的左值表达式强制转换为"引用T2"类型.T1T2void* 不是函数指针,对象没有函数或void类型.
[basic.types]
对象类型是(可能是cv限定的)类型,它不是函数类型,不是引用类型,也不是void类型.
所以也许我正在抓住稻草,但这似乎reinterpret_cast<void*>(func)是非法的.但是,另一方面,[expr.static.cast]/5表示"否则,static_cast应执行下面列出的转换之一.不应使用a明确执行其他转换static_cast." 关键区别是"应"和"可以".这足以使reinterpret_cast合法化还是我遗漏了别的东西?
Col*_*mbo 18
(所有引用均来自N3337,并且相当于每个草稿,直到N4296为止,这个答案至少对C++ 11和C++ 14有效,但对于C++ 03则不是这个答案的第一个引用在那里不存在.)
[expr.reinterpret.cast]/8:
有条件地支持将函数指针转换为对象指针类型(反之亦然).这种转换的含义是实现定义的,除非实现支持两个方向的转换,将一种类型的prvalue转换为另一种类型并返回,可能具有不同的cv-qualification,将产生orignal指针值.
这包含在您的商家信息中.你认为这void不是一个对象类型,但你没有考虑关键的[basic.compound]/3:
的类型的一个指针
void或指向对象类型被称为对象的指针类型.
(也就是说,对象指针类型不一定是"指向对象类型的指针" - 标准术语让你在那里.)
唯一的原因
f = reinterpret_cast<decltype(f)>(s);
Run Code Online (Sandbox Code Playgroud)
在GCC或Clang上是不行的是,与源表达式相反,目标类型不会衰减 - 并且您显然不能void*转换为函数类型.您需要使目标类型成为函数的指针,然后才能工作.