这是我上一个问题The address of a function matching a bool vs const void* overload的切线跟进。回答者解释说:
[C ++ 11]标准没有定义来自a的任何标准转换 "指向功能的指针"指向
void
的指针。"很难提供某些内容的缺席的引用,但是 我最接近的是C ++ 11 4.10 / 2 [conv.ptr]:
“指向 cv
T
指针”的prvalue,“其中T
是对象类型,可以转换为prvalue输入“指向 cv 的指针void
”。将“指向 cvT
”的指针转换为a的结果 “指向 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);
}
不太好:
void func() { }
int main() {
void* s = reinterpret_cast<void*>(func);
reinterpret_cast<decltype(func)>(s);
}
N3337首先说,
[expr.reinterpret.cast]
表达式
reinterpret_cast<T>(v)
的结果是结果 将表达式v
转换为T
类型。如果T
是左值 引用类型或函数类型的右值引用,结果是 左值;如果T
是对象类型的右值引用,则结果为 一个x值;否则,结果是一个prvalue和左值到右值 (4.1),数组到指针(4.2)和函数到指针(4.3)标准 转换是在表达式v。可以进行的转换上执行的 下面列出了使用reinterpret_cast
明确执行的操作。没有 可以使用reinterpret_cast
明确执行其他转换。
我粗犷的语言,我认为这是关键。最后一部分似乎暗示如果没有列出转换,那么它就是非法的。简而言之,允许的转换是:
X
&#34类型的T1
成员的指针;可以显式转换为不同类型的prvalue&#34;指向T2
&#34;类型Y的成员的指针如果T1
和T
2都是函数类型或两种对象类型。T1
的左值表达式可以转换为类型&#34;引用T2
&#34;如果表达式为&#34;指针T1
&#34;可以显式转换为类型&#34;指针T2
&#34;使用reinterpret_cast。 void*
不是函数指针,对象没有函数或void类型。
[basic.types]
对象类型是(可能是cv限定的)类型,不是a 函数类型,不是引用类型,也不是void类型。
所以也许我正在抓稻草,但似乎reinterpret_cast<void*>(func)
是非法的。但是,另一方面,[expr.static.cast] / 5表示&#34;否则,static_cast
将执行下面列出的转换之一。不得进行其他转换
使用static_cast
明确执行。&#34;关键的区别是&#34;应该&#34;和&#34;可以&#34;。这足以使reinterpret_cast
合法或我错过了其他什么吗?
答案 0 :(得分:18)
(所有引用均来自N3337,并且相当于每个草稿,直到N4296为止,即此答案至少对C ++ 11和C ++ 14 有效,但对C +无效+03 因为这个答案的第一个引用不存在。)
[expr.reinterpret.cast] / 8:
将函数指针转换为对象指针类型,反之亦然 有条件支持。这种转换的意义是 实现定义,但实现支持 双向转换,将一种类型的prvalue转换为 另一种类型和背面,可能具有不同的cv资格, 应产生原始指针值。
这包含在您的商家信息中。你认为void
不是对象类型,但你没有考虑关键[basic.compound] / 3:
指向
void
的指针的类型或指向对象类型的指针称为对象指针类型 。< / p>
(也就是说,对象指针类型不一定是&#34;指向对象类型&#34的指针; - 标准术语让你在那里。)
的唯一原因
f = reinterpret_cast<decltype(f)>(s);
对于GCC或者Clang来说,目标类型与源表达式相反,不已经衰减了 - 并且您显然不能将void*
强制转换为功能类型。您需要使目标类型成为函数的指针then it works。