C++20模板concat_callable拼接多函数调用时报参数类型转换错误
问题根因
当前实现的编译错误来自C++的类型推导规则:
- C++中lambda的默认返回值推导遵循
auto模板推导规则,会自动剥去返回值的引用、const等限定,将左值引用类型decay为对应的值类型 - 当拼接的函数数量为2时,递归链最内层直接返回原始函数对象,不存在中间嵌套lambda,函数返回的左值引用可以直接传递给外层函数,传参过程不会触发引用到值的类型转换,因此编译可以通过
- 当拼接的函数数量为3时,递归链中存在一层中间嵌套的lambda,该lambda因为默认
auto返回值推导,会把原本返回的std::string&左值引用decay为一个临时的std::string右值对象,外层函数尝试接收这个右值作为非const左值引用参数时,就会触发类型不匹配的编译错误
修复方案
只需要为拼接生成的lambda添加尾置decltype(auto)返回类型,让lambda的返回类型和内部表达式的类型完全匹配,完整保留所有引用、cv限定,不执行decay转换即可。
修复后的完整模板实现为:
template<typename Callable, typename... Callables> decltype(auto) concat_callable(Callable callable, Callables... callables) { if constexpr (sizeof...(callables) > 0) { return [=]<typename... Args>(Args&&... args) -> decltype(auto) { return callable(concat_callable(callables...)(std::forward<Args>(args)...)); }; } else { return callable; } }
验证效果
修复后三层调用的类型推导链和直接手写f1(f2(f3(str)))完全一致,每层嵌套传递的都是std::string&左值,不存在临时值拷贝或右值绑定问题,原有调用代码可以正常编译运行。
内容的提问来源于stack exchange,提问作者Michal
相关产品推荐
相关产品推荐

