C ++ 11 lambda含糊不清

时间:2013-11-12 16:51:19

标签: c++ c++11

为什么编译器不能选择最明显的重载:

#include <iostream>
#include <functional>

static void foo(const std::function<void(bool)>& f) {
    std::cerr << "using bool overload" << std::endl;
    f(true);
}

static void foo(const std::function<void(int)>& f) {
    std::cerr << "using int overload" << std::endl;
    f(1);
}

int main() {
    foo([](const bool value) {
        std::cout << std::boolalpha << value << std::endl;
    });
    foo([](const int value) {
        std::cout << value << std::endl;
    });
    return 0;
}

你会期望输出:

using bool overload
true
using int overload
1

但是,编译器无法推断出正确的重载:

gcc-4.8

main.cpp: In function 'int main()':
main.cpp:17:6: error: call of overloaded 'foo(main()::__lambda0)' is ambiguous
     });
      ^
main.cpp:17:6: note: candidates are:
main.cpp:4:13: note: void foo(const std::function<void(bool)>&)
 static void foo(const std::function<void(bool)>& f) {
             ^
main.cpp:9:13: note: void foo(const std::function<void(int)>&)
 static void foo(const std::function<void(int)>& f) {
             ^

clang-3.4

main.cpp:15:5: error: call to 'foo' is ambiguous
    foo([](const bool value) {
    ^~~
main.cpp:4:13: note: candidate function
static void foo(const std::function<void(bool)>& f) {
            ^
main.cpp:9:13: note: candidate function
static void foo(const std::function<void(int)>& f) {
            ^

这是因为std::function构造函数会自动使用和转换参数吗?

2 个答案:

答案 0 :(得分:0)

所以为了找到lambda的类型,这很有效:

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

template<typename F>
struct first_argument {
  template<typename Ret, typename A, typename... Rest>
  static A  helper(Ret (F::*)(A, Rest...));
  template<typename Ret, typename A, typename... Rest>
  static A helper(Ret (F::*)(A, Rest...) const);
  typedef decltype(helper(&F::operator())) type;
};

template <typename T>
static void foo(T f) {
    typedef typename first_argument<T>::type type;
    std::cerr << "using traits overload" << std::endl;
    std::cerr << "typename: " << typeid(type).name() << std::endl;
    f(true);
}

template<typename T>
static void foo(void (*f)(const T)) {
    std::cerr << "using function pointer overload" << std::endl;
    std::cerr << "typename: " << typeid(T).name() << std::endl;
    f(T());
}


int main() {
    const bool x = false;
    foo([](const bool value) {
        std::cout << std::boolalpha << value << std::endl;
    });
    const int i = 9;
    foo([i](const bool value) {
        std::cout << std::boolalpha << value << ':' << i << std::endl;
    });
    foo(+[](const bool value) {
        std::cout << std::boolalpha << value << std::endl;
    });
    foo(+[](const int value) {
        std::cout << value << std::endl;
    });
    foo([&x](const bool value) {
        std::cout << std::boolalpha << value << '|' << x << std::endl;
    });
    return 0;
}

运行here

答案 1 :(得分:0)

Lambda可能有一种时髦的语法,但它们仍然是有趣的。也就是说,他们定义了unique_type::operator()(Args...)。捕获lambda也是如此;捕获的值是lambda对象的成员。

因此,以下代码分解了一个lambda对象:

template<typename T, typename R, typename A>
void bar(T const& t, R (T::*pmf)(A));

template<typename LAMBDA>
void foo(LAMBDA const& l)
{
  bar(l, &LAMBDA::operator());
}

显然,如果您只需要在示例中区分两个lambda,则可以用两个非模板化函数替换bar。 OTOH,如果你需要支持具有任意数量参数的lambda,你需要一个bar的可变参数模板。