You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

显式指定返回类型后lambda调用重载函数仍存歧义的原因

问题解析与解决方案

这个编译错误的核心原因是**std::function<void(int)>的构造函数可以接受任何返回类型的可调用对象**——因为void类型的函数对象允许忽略返回值。而你的第二个lambda显式返回bool,它既可以被转换成std::function<bool(int)>,也可以被转换成std::function<void(int)>,编译器无法确定你要调用哪个重载,因此报出歧义错误。

反观第一个无显式返回的lambda,它的返回类型是void,无法满足std::function<bool(int)>对返回值的要求(void不能隐式转换为bool),所以只能匹配第一个重载,没有歧义。

需要注意的是,引用捕获本身和这个歧义问题无关——哪怕你用值捕获,只要lambda返回bool,同样会触发这个歧义。

解决方法

方法1:显式转换为目标std::function类型

直接把lambda包装成你想要的std::function类型,消除歧义:

do_some(std::function<bool(int)>([&](int in) -> bool {
    local_to_be_modified += in; 
    std::cout << "This is bool-" << std::endl; 
    return true; 
}));

方法2:使用SFINAE实现精确匹配重载

如果不想每次都显式转换,可以利用SFINAE(替换失败不是错误)技术,让重载只接受返回类型完全匹配的可调用对象。这样编译器会自动根据lambda的返回类型选择正确的重载:

#include <iostream>
#include <string>
#include <functional>
#include <type_traits>

// 只接受返回void的可调用对象
template<typename F>
auto do_some(F&& thing) -> std::enable_if_t<std::is_same_v<std::invoke_result_t<F, int>, void>> {
    thing(5);
}

// 只接受返回bool的可调用对象
template<typename F>
auto do_some(F&& thing) -> std::enable_if_t<std::is_same_v<std::invoke_result_t<F, int>, bool>> {
    if (thing(10)) {
        std::cout << "it's true!" << std::endl;
    }
}

int main() {
    int local_to_be_modified = 0;
    do_some( [&](int in) { 
        local_to_be_modified = in; 
        std::cout << "This is void-" << std::endl; 
    } );
    do_some( [&](int in) -> bool { 
        local_to_be_modified += in; 
        std::cout << "This is bool-" << std::endl; 
        return true; 
    } );
}

这个方案通过std::invoke_result_t获取可调用对象的返回类型,再用std::enable_if_t启用对应的重载,从根源上避免了歧义。

内容的提问来源于stack exchange,提问作者Dávid Tóth

火山引擎 最新活动