如何正确使用std::invoke_result_t?接收引用参数的lambda传入模板编译失败
错误原因
你代码的问题出在std::invoke_result的参数传递逻辑和foo函数的参数转发逻辑两处:
std::invoke_result_t<Fn, Args...>中的Args...需要对应实际传入函数的参数的类型和值类别,你给参数加了std::decay_t会剥离所有引用、cv限定符,直接把类型退化为值类型。对于第二个要求bool&(非常量左值引用)入参的lambda,invoke_result会判定你要给它传入一个纯右值bool,而纯右值无法绑定到非常量左值引用,自然不存在type成员,触发编译报错。- 你定义的foo函数形参是
const A& ...aA,传递给lambda的参数是常量左值引用,也无法绑定到第二个lambda要求的非const左值引用,哪怕改对invoke_result的写法,调用阶段也会报错。
修复方案
你需要使用万能引用+完美转发实现类似STL的参数传递逻辑,同时去掉std::decay_t对参数类型的错误处理,修改后的代码如下:
#include <type_traits> #include <iostream> #include <utility> template <typename F, typename... A> std::invoke_result_t<F&&, A&&...> foo(F&& aF, A&& ...aA) { return std::forward<F>(aF)(std::forward<A>(aA)...); } int main() { bool positive = true; std::cout << foo([](bool flag) -> int { return flag ? 1 : -1; }, positive) << '\n'; std::cout << foo([](bool& flag) -> int { flag = !flag; return flag ? 1 : -1; }, positive) << '\n'; // 可验证传入的positive已经被lambda修改 std::cout << std::boolalpha << positive << '\n'; return 0; }
修改说明
- 函数对象和参数都使用万能引用
T&&声明,配合std::forward可以完美保留参数的原值类别、cv限定符和引用属性,不管是值类型、左值引用、右值引用、常量/非常量参数都可以正确传递。 - 直接把转发后的参数类型传递给
std::invoke_result,保证类型判定和实际调用逻辑完全一致,同时兼容引用传参和值传参的场景。
内容的提问来源于stack exchange,提问作者GrumpyBloke
相关产品推荐
相关产品推荐

