使用 lambda 函数签名的函数重载

Function overload using lambda function signature

本文关键字:函数 重载 lambda 使用      更新时间:2023-10-16

考虑以下示例

void foo(const std::function<int()>& f) {
    std::cout << f() << std::endl;
}
void foo(const std::function<int(int x)>& f) {
std::cout << f(5) << std::endl;
}
int main() {
    foo([](){return 3;});
    foo([](int x){return x;});
}

这不会编译,因为据说对foo的调用是不明确的。据我了解,这是因为 lambda 函数不是先验的std::function,而是必须强制转换为它,并且有一个接受任意参数的std::function构造函数。

也许有人可以向我解释为什么有人会创建一个采用任意参数的隐式构造函数。但是,我的尖锐问题是是否有解决方法,它允许使用 lambda 函数的函数签名来重载函数foo。我尝试过函数指针,但这不起作用,因为捕获 lambda 函数不能转换为普通函数指针。

欢迎任何帮助。

根据

C++11,您的编译器是正确的。在 C++14 中,添加了一条规则,指出构造函数模板不得参与重载解析,除非参数的类型实际上可以用std::function的参数类型调用。因此,此代码应该在 C++14 中编译,而不是在 C++11 中编译。认为这是C++11中的疏忽。

现在,您可以通过显式转换来解决此问题:

foo(std::function<int()>([](){return 3;}));

http://coliru.stacked-crooked.com/a/26bd4c7e9b88bbd0

使用

std::function 的替代方法是使用模板。 模板避免了与 std::function 关联的内存分配开销。 模板类型推断机制将推断传递的 lambda 的正确类型,以便调用站点强制转换消失。 但是,您仍然需要消除无参数与参数情况的重载的歧义。

您可以使用行为类似于enable_if的尾随返回类型的技巧来执行此操作。

template<typename Callable>
auto baz(Callable c) 
    -> decltype(c(5), void())
{
    std::cout << c(5) << std::endl;
}

上述 baz 重载仅在可以使用参数 5 调用模板参数 Callable 时才是有效的重载候选项。

您可以在此之上放置更高级的机制以使其更通用(即将参数的可变参数包扩展为可调用),但我想展示基本机制的工作原理。