std::function模板参数解析:void()这类类型究竟是什么?
你提的这个问题戳中了C++里函数类型和函数指针类型的关键区别,很多刚接触std::function的开发者都会在这里卡壳。咱们一步步拆解:
首先:void()、int(int,int)是函数类型,不是函数指针
你尝试的这段代码报错,本质就是混淆了函数类型和函数指针类型:
int main() { using type = void(); type x = printer; }
编译器给出的报错信息很直接:
main.cpp:15:10: warning: declaration of 'void x()' has 'extern' and is initialized
type x = printer;
^
main.cpp:15:14: error: function 'void x()' is initialized like a variable
type x = printer;
^~~~~~~
原因是type被定义成了函数类型(描述一个无参、返回void的函数),而你试图把printer(函数名会隐式转成函数指针)赋值给一个函数类型的"变量"——但C++里函数本身不是可赋值的对象,你不能像定义普通变量那样定义一个函数类型的变量并给它赋值。
对比一下函数指针类型:
using type = void(*)(); // 这是函数指针类型 type x = printer; // 完全合法,printer隐式转成函数指针赋值给x
简单总结:
void():描述的是函数本身的类型,比如printer这个函数的类型就是void()void(*)():描述的是指向这类函数的指针类型,是可以存储函数地址的变量类型
然后:std::function的模板参数要的就是这个函数类型
std::function的核心能力是类型擦除,它需要知道的不是你要存储的对象具体是什么类型,而是这个对象能以什么样的签名被调用——而函数类型正好就是用来描述这个调用签名的。
比如你给出的示例:
#include <functional> #include <iostream> void printer() { std::cout << "I print!"; } int adder(int a, int b) { return a + b; } int main() { std::function<void()> fun1 = printer; // 匹配无参、返回void的调用签名 std::function<int(int, int)> fun2 = adder; // 匹配双int参数、返回int的调用签名 std::function<void()> fun3 = [](){}; // 无参无返回的lambda也符合签名 std::function<int(int, int)> fun4 = [](int a, int b) { return a + b; }; // lambda匹配签名 }
std::function不关心你塞进去的是普通函数、lambda还是仿函数,只要这个对象能以模板参数指定的函数类型签名被调用,它就能统一包装并存储。这也是它灵活性的核心来源。
额外补充:能不能用函数指针类型当std::function的模板参数?
理论上可以,比如std::function<void(*)()>是合法的,但这完全浪费了std::function的设计初衷。因为这种情况下,它只能存储函数指针,而不能存储有捕获的lambda(有捕获的lambda无法隐式转成函数指针)或者自定义仿函数了——等于把它降级成了一个普通的函数指针容器,失去了泛型存储的能力。
所以std::function设计成接收函数类型作为模板参数,就是为了聚焦"调用行为",而不是具体的对象类型,这才是它作为通用可调用对象容器的价值所在。
内容的提问来源于stack exchange,提问作者Fureeish

