C++ std::invoke显式指定模板参数实现完美转发为何编译失败?
C++代码编译失败原因分析
f3编译失败的本质是显式指定std::invoke模板参数导致的参数类型匹配错误,具体原因拆解如下:
前置逻辑
- 调用
f3([](const char*) {})时,传入的匿名lambda是右值,f3的模板参数F作为转发引用的推导结果是无引用修饰的lambda原生类型。 - f3函数体内的参数名
f属于左值:所有有名字的变量,哪怕本身的类型是右值引用,语法上都归类为左值。
三个函数的实现差异
f1的逻辑:std::forward<F>(f)会把左值f强制转为F&&右值,右值调用lambda默认的const operator()完全合法,因此编译通过。f2的逻辑:
没有显式指定std::invoke的模板参数,编译器自动推导:因为实参f是左值,std::invoke的第一个形参是转发引用,推导得到的第一个模板参数为F&。此时std::invoke内部会用std::forward<F&>(f)保留左值属性,左值调用lambda的operator()合法,编译通过。f3的错误原因:
你显式指定了std::invoke的第一个模板参数为F(无引用的lambda类型),此时std::invoke的第一个形参类型为F&&,也就是非const右值引用。C++语法明确规定左值不能绑定到非const右值引用,因此参数匹配直接失败,无法通过编译。
补充:std::invoke的完美转发正确写法
如果想要用std::invoke实现和f1等价的完美转发效果,应该直接转发functor本身,而非显式指定模板参数:
template <typename F> void f3_fixed(F&& f) { std::invoke(std::forward<F>(f), "hi"); }
内容的提问来源于stack exchange,提问作者Zizheng Tai
相关产品推荐
相关产品推荐

