使用 lambda 函数签名的函数重载
Function overload using lambda function signature
考虑以下示例
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 的正确类型,以便调用站点转换消失。但是,您仍然需要消除无参数与有参数情况下的重载歧义。
您可以使用一个技巧来完成此操作,其尾随 return 类型的行为类似于 enable_if。
template<typename Callable>
auto baz(Callable c)
-> decltype(c(5), void())
{
std::cout << c(5) << std::endl;
}
只有当模板参数 Callable 可以用参数 5 调用时,上述 baz 重载才是有效的重载候选者。
您可以在此之上放置更高级的机制以使其更通用(即,将 args 的可变参数包扩展为可调用)但我想展示基本机制的工作原理。
考虑以下示例
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 的正确类型,以便调用站点转换消失。但是,您仍然需要消除无参数与有参数情况下的重载歧义。
您可以使用一个技巧来完成此操作,其尾随 return 类型的行为类似于 enable_if。
template<typename Callable>
auto baz(Callable c)
-> decltype(c(5), void())
{
std::cout << c(5) << std::endl;
}
只有当模板参数 Callable 可以用参数 5 调用时,上述 baz 重载才是有效的重载候选者。
您可以在此之上放置更高级的机制以使其更通用(即,将 args 的可变参数包扩展为可调用)但我想展示基本机制的工作原理。