消除对使用std :: functions的函数的调用

时间:2010-11-06 02:52:21

标签: c++ function lambda c++11 ambiguity

下面的代码不能在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;});
}

2 个答案:

答案 0 :(得分: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);

因此,编译器无法在重载决策期间知道要选择foostd::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); }

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

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

答案 1 :(得分: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一样正常。