C++11 Lambda 函数隐式转换为 bool 与 std::function

标签 c++ c++11 lambda overloading

考虑这个简单的示例代码:

#include <functional>
#include <iostream>

void f(bool _switch) {
    std::cout << "Nothing really" << std::endl;
}

void f(std::function<double (int)> _f) {
    std::cout << "Nothing really, too" << std::endl;
}

int main ( int argc, char* argv[] ) {
    f([](int _idx){ return 7.9;});
    return 0;
}

编译失败:

$ g++ --std=c++11 main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:15:33: error: call of overloaded ‘f(main(int, char**)::<lambda(int)>)’ is ambiguous
main.cpp:15:33: note: candidates are:
main.cpp:6:6: note: void f(bool)
main.cpp:10:6: note: void f(std::function<double(int)>)

但是,如果我用一个引用参数替换第二个函数,它就可以正常编译。如果它被 const 引用替换,它会再次失败。

所以我对这个例子有一些疑问:

  • 为什么 lambda 函数首先可以隐式转换为 bool
  • 为什么采用 std::function 引用可以解决歧义?
  • 对我来说最重要的是,我该如何避免这个问题?我需要第二个函数来获取 std::function 的(拷贝)或对它的 const 引用。

最佳答案

可以将没有捕获的 lambda 函数转换为常规函数指针,然后将其标准转换为 bool。

如果您通过非常量引用获取 std::function,那么这会将它排除在候选者之外,因为将 lambda 转换为 std::function 需要临时的,临时的不能绑定(bind)到非常量引用。这只留下 f(bool) 作为候选,所以没有歧义。

有很多方法可以避免歧义。例如,您可以先创建一个 std::function 变量:

std::function<double(int)> g = [](int _idx){ return 7.9;};
f(g);

或者你可以转换 lambda:

f(std::function<double(int)>([](int _idx){return 7.9;}));

你可以有一个辅助函数:

template<typename T>
std::function<T> make_function(T *f) { return {f}; } 

int main ( int argc, char* argv[] ) {
    f(make_function([](int _idx){ return 7.9;}));
    return 0;
}  

或者您可以获取您感兴趣的特定功能:

int main ( int argc, char* argv[] ) {
    void (*f_func)(std::function<double(int)>) = f;
    f_func([](int _idx){ return 7.9;});
    return 0;
}

关于C++11 Lambda 函数隐式转换为 bool 与 std::function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23162654/

相关文章:

c++ - realloc 函数不会为我保留现有内存

c++ - 检测引用计数智能指针内存泄漏的设计模式

c++ - 使用 std::move 来防止复制

c++ - 为什么我不能将 [](auto&&...){} 转换为 std::function<void()>?

lambda - F# 中的高阶函数

java - Netbeans 中的 Lambda 表达式问题

c++ - 在 win32 上编译 idl 文件时出现 midl 错误 2025(midl 不喜欢 string<40>)

抽象类的 C++ 继承

c++ - 如何在 C++11 中为 OuterClass 制作复制粘贴友好的 typedef?

c++ - 健壮的 C++ 事件模式