C++ 使用reinterpret_cast将函数强制转换为void*,为什么不';这不违法吗?

C++ 使用reinterpret_cast将函数强制转换为void*,为什么不';这不违法吗?,c++,pointers,c++11,language-lawyer,C++,Pointers,C++11,Language Lawyer,这是对我上一个问题的一个切向的跟进。回答者解释说: [C++11]标准没有定义从 “指向函数的指针”指向“指向void的指针” 很难为缺少的东西提供报价,但是 我能做的最接近C++11 4.10/2[conv.ptr]: “指向cv的指针T”类型的PR值,其中T是对象类型,可以转换为“指向cv的指针”类型的PR值 void”。将“指向cvT”的指针转换为 “指向cvvoid”的指针指向存储位置的开始 类型为T的对象所在的位置,就好像该对象是一个most T类型的派生对象(1.8)(即,不是基类子

这是对我上一个问题的一个切向的跟进。回答者解释说:

[C++11]标准没有定义从 “指向函数的指针”指向“指向
void
的指针”

很难为缺少的东西提供报价,但是 我能做的最接近C++11 4.10/2[conv.ptr]:

“指向cv的指针
T
”类型的PR值,其中
T
是对象类型
,可以转换为“指向cv的指针”类型的PR值
void
”。将“指向cv
T
”的指针转换为 “指向cv
void
”的指针指向存储位置的开始 类型为
T
的对象所在的位置,就好像该对象是一个most T类型的派生对象(1.8)(即,不是基类子对象)。 空指针值将转换为 目的地类型

(强调矿山)

假设
func
被声明为
void func(),如果执行C样式转换,即
(void*)func
,则转换将成功<代码>静态转换(func)
但是无效,但是
重新解释转换(func)
将成功。但是,您不能将随后转换的指针转换回其原始类型。比如说,

罚款:

intmain(){
int*i;
void*s=静态铸件(i);
i=静态铸件;
s=重新解释铸件(i);
i=重新解释铸件;
}
不好:

void func() { }

int main() {
  void* s = reinterpret_cast<void*>(func);
  reinterpret_cast<decltype(func)>(s);
}
void func(){}
int main(){
void*s=重新解释(func);
重新解释铸件;
}
首先说

[expr.reinterpret.cast]

表达式
重新解释(v)
的结果是 将表达式
v
转换为类型
T
。如果
T
是左值 引用类型或函数类型的右值引用,结果为 左撇子;如果
T
是对对象类型的右值引用,则结果为 xvalue;否则,结果将是一个prvalue和一个从左值到右值的转换 (4.1)、数组到指针(4.2)和函数到指针(4.3)标准 对表达式v执行转换可以进行的转换 下面列出了使用
reinterpret\u cast
显式执行的步骤。不 其他转换可以使用
reinterpret\u cast

我把我认为是关键的语言加粗了。最后一部分似乎暗示,如果转换未列出,则是非法的。简言之,允许的转换为:

  • 指针可以显式转换为任何足以容纳它的整数类型
  • 整数类型或枚举类型的值可以显式转换为指针
  • 函数指针可以显式转换为不同类型的函数指针
  • 对象指针可以显式转换为不同类型的对象指针
  • 有条件地支持将函数指针转换为对象指针类型,或将函数指针转换为对象指针类型
  • 空指针值(4.10)转换为目标类型的空指针值
  • 如果
    T1
    类型的“指向
    X
    成员的指针”和
    T
    类型都是函数类型或对象类型,则可以将类型为“指向
    T2
    类型的Y成员的指针”的PR值显式转换为不同类型的PR值
  • 如果“指向
    T1
    的指针”类型的表达式可以使用重新解释转换显式转换为“指向
    T2
    ”类型,则类型为
    T1
    的左值表达式可以转换为类型“引用
    T2
void*
不是函数指针,对象没有函数或void类型

[基本类型]

对象类型是(可能是cv限定的)不是 函数类型,不是引用类型,也不是void类型

所以,也许我是在抓救命稻草,但看来重新解释cast(func)是非法的。但是,另一方面,[expr.static.cast]/5表示“否则,
static\u cast
将执行下面列出的转换之一。不得执行其他转换 使用
static\u cast
“显式执行,关键区别在于“应”和“可”。这足以使
重新解释
合法吗?还是我遗漏了其他内容?

(所有引用都来自N3337,并且在N4296之后的每一份草稿中都是等效的,也就是说,这个答案至少对C++11和C++14有效,但对C++03无效,因为这个答案的第一个引用在那里不存在。)

[expr.reinterpret.cast]/8:

将函数指针转换为对象指针类型,或将函数指针转换为对象指针类型 是有条件支持的。这种转换的含义是 定义了实现,除非实现支持 双向转换,将一种类型的PR值转换为 另一种类型和背面,可能具有不同的cv资格, 应产生原始指针值

这包含在您的列表中。您认为Value<代码>不是一个对象类型,但是您没有考虑关键的[Basic,Cult] /3:

指向
void
的指针或指向对象类型的指针的类型称为对象指针类型

(也就是说,对象指针类型不一定是“指向对象类型的指针”——这是标准术语让您明白的。)

唯一的原因是

f = reinterpret_cast<decltype(f)>(s);
f=重新解释铸件;
与源表达式相反,目标类型没有衰减——而且显然不能将
void*
强制转换为函数类型。您需要创建目标类型
f = reinterpret_cast<decltype(f)>(s);