为何含std::function入参的类仅支持括号初始化,无法用赋值初始化?
问题描述
假设有如下类,其构造函数接收const std::function<int(void)>&类型的可调用对象:
class SomeClass { public: SomeClass(const std::function<int(void)>& callable) { ... } };
另有自由函数:
int some_function() { return 0; }
实际使用时出现以下现象:
- 括号初始化(直接初始化)类实例可正常运行:
SomeClass object_one(some_function); SomeClass object_three(&some_function); - 赋值初始化(复制初始化)类实例则报错,MSVC C++14环境下的错误信息分别为:
SomeClass object_two = some_function:不存在从int ()转换为<unnamed>::SomeClass的合适构造函数SomeClass object_four = &some_function:不存在从int (*)()转换为<unnamed>::SomeClass的合适构造函数
但直接初始化std::function对象时,以下四种方式均正常:
std::function<int(void)> callable_1(some_function); std::function<int(void)> callable_2 = some_function; std::function<int(void)> callable_3(&some_function); std::function<int(void)> callable_4 = &some_function;
请问构造函数是否存在缺失?此现象的原因是什么?
原因分析与结论
构造函数不存在缺失:当前定义的构造函数完全满足需求,问题根源在于C++对不同初始化方式的隐式转换规则限制不同。
核心差异:直接初始化与复制初始化的隐式转换次数限制
- 直接初始化(括号形式):允许多次隐式转换。初始化
object_one或object_three时,编译器会先将some_function(或其指针)隐式转换为std::function<int(void)>临时对象,再将该对象传入SomeClass的构造函数,这两次转换符合规则,因此可以正常编译。 - 复制初始化(赋值形式):仅允许一次隐式转换。编译器需要从
some_function(或函数指针)直接生成SomeClass对象,但不存在这样的直接转换路径——必须先转为std::function再转为SomeClass,这属于两次隐式转换,违反了C++的规则,因此触发编译错误。
- 直接初始化(括号形式):允许多次隐式转换。初始化
std::function四种初始化方式均可行的原因:无论使用直接初始化还是复制初始化,都是将函数指针直接转换为
std::function对象,仅涉及一次隐式转换,符合C++的转换规则,因此全部可以正常编译。
内容的提问来源于stack exchange,提问作者Jozef Nagy
相关产品推荐
相关产品推荐

