为什么返回和非返回std::functions是可转换的?
为什么这样做?
std::function<int(int)> ret_func = [](int x) { return x; };
std::function<std::string(int)> ret_func1 = [](int x) { return std::to_string(x); };
std::function<void(int)> func = ret_func;
std::function<void(int)> func1 = ret_func1;
由于std::function? 中函子的类型擦除?这个转换在任何类型的函数之间都不起作用;例如,如果您更改参数并尝试分配给另一个参数,std::function为什么这不起作用?因为返回值不会改变函子的类型而参数呢?
现场演示
回答
不要将其视为铸造,而是将其视为std::function<int(int)>被分配给std::function<void(int)>作为值。
-
std::function<void(int)>可以分配任何fun可以像调用一样的函数式对象static_cast<void>(fun(v))(v作为一个int)。 -
std::function<int(int)>很容易符合该标准,因为您可以执行以下操作:
void foo(std::function<int(int)> fun) {
fun(12);
}
所以std::function<int(int)>必须可分配给std::function<void(int)>. 这里的所有都是它的。
图书馆如何实现这一点并不重要。它只是为了履行 API 合同。
免责声明:这有点过于简单化了。该标准实际上对std::function->std::function赋值有一些规定,例如移动构造和处理未赋值的std::functionss。但是,此答案中概述的语义原则仍然可以作为解释。
正如所问,标准的相关部分:
[func.wrap]
模板函数(F f); 约束:对于参数类型 ArgTypes... 和返回类型 R,F 是 Lvalue-Callable ([func.wrap.func])。
如果表达式 INVOKE(declval<F&>(), declval()...) 被视为未求值的操作数,并且是格式良好的 ([func.要求])。
[func.require]
将 INVOKE(f, t 1 , t 2 , ..., t N ) 定义为 static_cast<void>(INVOKE(f, t 1 , t 2 , ..., t N )) 如果 R 是 cv void,否则为 INVOKE(f, t 1 , t 2 , …, t N ) 隐式转换为 R。
所以既然std::function<int(int)>是 Lvalue-Callable for void(int),那么它就是一个有效值。现在,在实践中,这实际上并没有发挥作用,因为其他构造函数/赋值运算符会拦截它,但语义仍然存在。