5

下面的代码不能在 gcc 4.5 上编译,因为对 foo 的调用是不明确的。消除歧义的正确方法是什么?

#include <iostream>
#include <functional>
using namespace std;

void foo(std::function<void(int, int)> t)
{
    t(1, 2);
}

void foo(std::function<void(int)> t)
{
    t(2);
}

int main()
{
    foo([](int a, int b){ cout << "a: " << a << " b: " << b << endl;});
}
4

2 回答 2

6

最好的方法是显式创建一个std::function正确类型的对象,然后将该对象传递给函数:

std::function<void(int, int)> func = 
    [](int a, int b) { cout << "a: " << a << " b: " << b << endl; }
foo(func);

或内联:

foo(
    std::function<void(int, int)>(
        [](int a, int b) { cout << "a: " << a << "b: " << b << endl; }
));

std::function有一个接受任何东西的构造函数模板:

template<class F> function(F);

正因为如此,在重载决议期间编译器无法知道foo选择哪个:两者std::function<void(int)>都有std::function<void(int, int)>一个可以将您的 lambda 表达式作为参数的构造函数。

当您std::function直接传递一个对象时,std::function在重载决议期间首选复制构造函数,因此选择它而不是构造函数模板。


以后回答: 如果保证捕获列表为空,也可以使用普通函数指针。在 C++0x 中,无捕获 lambda 可隐式转换为函数指针。所以,你可以使用类似的东西

void foo(void (*t)(int, int)) { t(1, 2); }

void foo(void (*t)(int)) { t(1); }

foo直接使用无捕获 lambda(或具有匹配类型的函数指针)调用。

请注意,这种转换是语言标准草案的最新补充(它是在今年 2 月添加的),因此它不太可能得到广泛支持。Visual C++ 2010 还不支持它;我不知道最新的 g++。

于 2010-11-06T02:56:10.593 回答
3

我最近一直在考虑一个类似的问题,在寻找任何已知的解决方案时,我遇到了这篇文章并且缺乏解决方案

另一种解决方案是将仿函数抽象为模板参数并使用 decltype 来解析其类型。因此,上面的示例将变为:

#include <iostream>
#include <functional>
using namespace std;

template<class F>
auto foo(F t) -> decltype(t(1,2))
{
    t(1, 2);
}

template<class F>
auto foo(F t) -> decltype(t(2)) 
{
    t(2);
}

int main()
{
     foo([](int a, int b){ cout << "a: " << a << " b: " << b << endl;});
}

这在 gcc 4.5 中按预期工作。

于 2011-07-29T04:20:31.177 回答