c++ - 无法推断函数返回类型
问题描述
这不适用于 gcc-10 或 clang-10。
template <typename R, typename T>
auto invoke_function(R (&f)(T), T t) { return std::invoke(f, t); }
invoke_function(std::to_string, 42);
这适用于 gcc-10,但不适用于 clang-10。
template <typename R, typename T>
auto invoke_function(T t, R (&f)(T)) { return std::invoke(f, t); }
invoke_function(42, std::to_string);
在所有情况下,错误消息都非常相似:“无法推断模板参数'R'”或“无法推断模板参数'R'”(gcc)。
目前尚不清楚为什么此代码被拒绝。既然T
推导出来,std::to_string
就可以确定 的过载。对参数顺序的依赖特别烦人。它不应该只是工作吗?
我知道这个问题可以通过引入一个函数对象来回避:
struct to_string
{
template<typename T> std::string operator()(T t) { return std::to_string(t); }
};
然后就使用std::invoke
它。然而,这需要为每个重载集创建一个单独的函数对象。
有没有更好的办法?
解决方案
目前尚不清楚为什么此代码被拒绝。既然
T
推导出来,std::to_string
就可以确定 的过载。
这不是它的工作原理。模板推导首先独立地推导每个参数/参数对- 然后我们将所有推导放在一起并确保它们是一致的。所以我们T
从推断42
,然后分别R(&)(T)
从推断std::to_string
。但是每个重载都std::to_string
匹配该模式,所以我们不知道该选择哪一个。
但只有当我们能够独立地推断出每一对时,上述情况才是正确的。如果一个参数是不可推导的,我们跳过它,然后尝试返回并稍后填写。这就是这里的关键——我们重新构造推导,使得我们只推导:T
42
template <typename T>
auto invoke_function(std::string (&f)(std::type_identity_t<T>), T t) { return std::invoke(f, t); }
在这里,我们推断T
,int
现在我们std::string(&)(int)
从推断std::to_string
。现在可以使用,因为只有一个重载与该模式匹配。
除了现在这是未定义的行为,根据[namespace.std]/6:
Let
F
表示标准库函数 ([global.functions])、标准库静态成员函数或标准库函数模板的实例化。除非F
被指定为可寻址函数,否则如果 C++ 程序显式或隐式尝试形成指向F
.
std::to_string
不是一个可寻址的函数。
所以真正更好的方法是只包装to_string
一个 lambda 并传递它:
invoke_function([](auto x){ return std::to_string(x); }, 42);
并且只是调整invoke_function
以采用任意可调用而不是专门的函数。该 lambda 包装概括为:
#define FWD(x) static_cast<decltype(x)&&>(x)
#define LIFT(name) [&](auto&&... args) noexcept(noexcept(name(FWD(args)...))) -> decltype(name(FWD(args)...)) { return name(FWD(args)...); }
invoke_function(LIFT(std::to_string), 42);
推荐阅读
- mongodb - 由于 WiredTiger.turtle 权限,Mongodb 无法启动
- logic - 一阶逻辑 - 量词的位置
- mono - 在没有预编译的情况下在覆盆子上安装单声道
- java - 如何自动化连接(和修改)到外部服务器的测试
- graphql - ApolloBoost 使用不受支持的选项进行初始化:
- haskell - 如何解释 Haskell +RTS -s 摘要输出
- python - 重命名python列表中的项目
- sql - “select * from table_name”和“select a.* from table_name a”之间的技术区别是什么?
- php - 在调用另一个函数之前返回
- mysql - Mysql数据包括文本样式到html