You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中std::invoke能否自动匹配左值/右值引用重载?

std::invoke 与重载函数、完美转发的问题

示例代码

#include <iostream>
#include <functional>

using namespace std;

int func_invk_lr(int& a) {
    cout << "call left" << endl;
    return a;
}

int func_invk_lr(int&& a) {
    cout << "call right" << endl;
    return a;
}

template<typename T>
void call_invk_lr(T&& a) {
    std::invoke(func_invk_lr, a); // 错误:无法解析重载函数类型
    std::invoke(func_invk_lr, std::forward<T>(a)); // 错误:无法解析重载函数类型
}

int main() {
    int a = 1;
    std::invoke(func_invk_lr, a);    // 错误:无法解析重载函数类型
    std::invoke(func_invk_lr, 1);    // 错误:无法解析重载函数类型

    call_invk_lr(a);
    call_invk_lr(1); 
}

疑问

  1. std::invoke是否能够识别左值或右值实参,进而调用对应的重载函数?
  2. 若std::invoke可按预期工作,在模板函数的T&&参数场景下,是否仍需使用std::forward传递参数?

解答

问题1:std::invoke能否识别左右值实参调用对应重载?

代码报错的核心并非std::invoke无法识别左右值,而是编译器无法确定要传入std::invoke的func_invk_lr具体是哪个重载版本。std::invoke的第一个参数需要明确的可调用对象类型,而重载函数名本身属于未解析的重载类型,编译器无法自动推导匹配的重载。

只要帮编译器明确指定重载版本,std::invoke完全可以根据实参的左右值属性调用对应重载。示例:

int a = 1;
// 明确指定左值引用版本的重载
std::invoke(static_cast<int(&)(int&)>(func_invk_lr), a); // 输出 call left
// 明确指定右值引用版本的重载
std::invoke(static_cast<int(&)(int&&)>(func_invk_lr), 1); // 输出 call right

问题2:模板T&&场景下是否需要std::forward?

当std::invoke能正常工作(即已明确重载版本),模板的T&&参数场景下必须使用std::forward<T>(a)传递参数,以此实现完美转发:

  • 若传入左值,std::forward保留其左值属性,确保std::invoke调用左值版本重载;
  • 若传入右值,std::forward还原其右值属性,确保std::invoke调用右值版本重载。

修改后的模板函数示例(通过lambda让编译器自动推导重载):

template<typename T>
void call_invk_lr(T&& a) {
    std::invoke([](auto&& arg) {
        return func_invk_lr(std::forward<decltype(arg)>(arg));
    }, std::forward<T>(a));
}

此时调用call_invk_lr(a)会触发左值重载,调用call_invk_lr(1)会触发右值重载,完美转发的作用在这里不可或缺。

内容的提问来源于stack exchange,提问作者Zeyu Zhang CN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:28:14