为什么返回和非返回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)>作为

  1. std::function<void(int)>可以分配任何fun可以像调用一样的函数式对象static_cast<void>(fun(v))v作为一个int)。

  2. 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),那么它就是一个有效值。现在,在实践中,这实际上并没有发挥作用,因为其他构造函数/赋值运算符会拦截它,但语义仍然存在。


以上是为什么返回和非返回std::functions是可转换的?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>