使用ref限定符的std::invoke调用问题:如何启用左值引用重载?
如何正确调用带左值引用限定符的operator()重载?
当为operator()添加引用限定符后,使用std::invoke调用左值版本时会出现编译错误,具体代码及报错如下:
问题代码
#include <functional> struct F { void operator()() & {} void operator()() && {} // 注释此重载可编译通过 }; int main() { F f; std::invoke(&F::operator(), f); }
编译报错
<source>: In function 'int main()': <source>:10:15: error: no matching function for call to 'invoke(<unresolved overloaded function type>, F&)' 10 | std::invoke(&F::operator(), f); | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ In file included from <source>:1: /opt/compiler-explorer/gcc-trunk-20220731/include/c++/13.0.0/functional:107:5: note: candidate: 'template<class _Callable, class ... _Args> constexpr std::invoke_result_t<_Fn, _Args ...> std::invoke(_Callable&&, _Args&& ...)' 107 | invoke(_Callable&& __fn, _Args&&... __args) | ^~~~~~ /opt/compiler-explorer/gcc-trunk-20220731/include/c++/13.0.0/functional:107:5: note: template argument deduction/substitution failed: <source>:10:15: note: couldn't deduce template parameter '_Callable' 10 | std::invoke(&F::operator(), f); | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ ASM generation compiler returned: 1 <source>: In function 'int main()': <source>:10:15: error: no matching function for call to 'invoke(<unresolved overloaded function type>, F&)' 10 | std::invoke(&F::operator(), f); | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ In file included from <source>:1: /opt/compiler-explorer/gcc-trunk-20220731/include/c++/13.0.0/functional:107:5: note: candidate: 'template<class _Callable, class ... _Args> constexpr std::invoke_result_t<_Fn, _Args ...> std::invoke(_Callable&&, _Args&& ...)' 107 | invoke(_Callable&& __fn, _Args&&... __args) | ^~~~~~ /opt/compiler-explorer/gcc-trunk-20220731/include/c++/13.0.0/functional:107:5: note: template argument deduction/substitution failed: <source>:10:15: note: couldn't deduce template parameter '_Callable' 10 | std::invoke(&F::operator(), f); | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ Execution build compiler returned: 1
解决方法
报错核心原因是:存在两个带不同引用限定符的operator()重载,编译器无法自动解析&F::operator()指向哪个版本,必须显式指定或转换。
方法1:显式转换为左值版本的成员函数指针
通过类型别名明确左值版本的函数签名,再用static_cast转换:
#include <functional> struct F { void operator()() & {} void operator()() && {} }; int main() { F f; // 定义左值版本的成员函数指针类型 using LValueFuncPtr = void (F::*)() &; std::invoke(static_cast<LValueFuncPtr>(&F::operator()), f); }
方法2:直接调用(最简洁)
如果不需要std::invoke,直接调用左值对象的operator(),编译器会自动匹配左值版本:
int main() { F f; f(); // 自动匹配void operator()() & }
方法3:用lambda封装适配invoke场景
如果必须使用std::invoke,可以用lambda包装调用逻辑,绕过重载解析问题:
int main() { F f; std::invoke([&f](){ f(); }); }
原理说明
带引用限定符的成员函数会生成不同的函数指针类型:
void (F::*)() &:仅能绑定到左值对象的成员函数指针void (F::*)() &&:仅能绑定到右值对象的成员函数指针
直接写&F::operator()时,编译器无法从后续的左值参数f推导要选择哪个重载,必须显式指定类型才能确定目标函数。
内容的提问来源于stack exchange,提问作者user3882729
相关产品推荐
相关产品推荐

