4

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

#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构造函数会自动消费和转换参数?

4

2 回答 2

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;
}

在这里运行

于 2013-11-12T17:46:54.217 回答
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.

于 2013-11-13T13:22:35.503 回答