表达式fun与&fun的类型是否相同?为何断言与typeid结果矛盾?
嘿,这个问题问到点子上了——这其实是C++里函数名的隐式转换规则和typeid的特殊行为共同导致的,咱们掰开揉碎了说:
1. 为什么两次static_assert都能通过?
这是因为函数名在大多数表达式语境中会自动退化为指向自身的函数指针——当你把fun作为实参传给模板函数check时,编译器会自动把它转换成void(*)()类型的指针,和你指定的模板参数Check完全匹配,所以断言通过。
而&fun是显式获取函数的地址,它的类型本身就是void(*)(),自然也符合断言要求,所以两次断言都成功。
2. 为什么typeid的输出不一样?
typeid是个特例!它不会触发函数名到指针的隐式转换——当你对fun使用typeid时,fun在这里是函数类型的左值(它的本质类型是void(),也就是无参无返回的函数类型),所以typeid(fun)返回的是函数类型的信息,对应你看到的FvvE(编译器的类型编码,F代表function,vv表示无参数、无返回值)。
而&fun是明确的函数指针类型void(*)(),所以typeid(&fun)返回的是指针类型的信息,编码就是PFvvE(P代表pointer,后面的FvvE表示指向的函数类型)。
3. 额外验证:用decltype看本质
你可以用decltype来直接查看它们的原始类型,更直观:
#include <type_traits> void fun() {} using FuncType = void(); using FuncPtrType = void(*)(); // 这两个断言都会成立 static_assert(std::is_same_v<decltype(fun), FuncType>); static_assert(std::is_same_v<decltype(&fun), FuncPtrType>);
这里decltype(fun)直接获取了函数的原始类型void(),而decltype(&fun)是函数指针类型。
总结
一句话说清楚:函数名fun本身的类型是函数类型(void()),但在绝大多数表达式场景(比如传参、赋值给指针变量)中会自动转为函数指针类型(void(*)());只有少数特殊场景(比如typeid操作、decltype直接取函数名)会保留它的函数类型本质。这就是为什么你的static_assert都通过,但typeid输出不同的原因。
内容的提问来源于stack exchange,提问作者NPS

