开发者

Disambiguating calls to functions taking std::functions

开发者 https://www.devze.com 2023-01-23 14:03 出处:网络
The code below doesn\'t compile on gcc 4.5 because the call to foo is ambiguous.What is the correct way to disambiguate it?

The code below doesn't compile on gcc 4.5 because the call to foo is ambiguous. What is the correct way to disambiguate it?

#include <iostream>
#incl开发者_运维问答ude <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;});
}


The best way is to explicitly create a std::function object of the correct type then pass that object to the function:

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

or inline:

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

std::function has a constructor template that accepts anything:

template<class F> function(F);

Because of this, there's no way for the compiler to know during overload resolution which foo to select: both std::function<void(int)> and std::function<void(int, int)> have a constructor that can take your lambda expression as an argument.

When you pass a std::function object directly, the std::function copy constructor is preferred during overload resolution, so it is selected instead of the constructor template.


Answer for the future: If the capture list is guaranteed to be empty, you can also use ordinary function pointers. In C++0x, a captureless lambda is implicitly convertible to a function pointer. So, you can use something like

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

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

and call foo directly with the captureless lambda (or a function pointer with matching type).

Note that this conversion is a very recent addition to the draft language standard (it was added in February of this year), so it is not likely to be widely supported yet. Visual C++ 2010 doesn't support it yet; I don't know about the latest g++.


I've recently been thinking about a similar problem and when looking around for any known solutions I came across this post and lack of solutions for resolving

An alternative solution is to abstract over the functor as a template argument and use decltype to resolve its type. So, the above example would become:

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

This works as expected with gcc 4.5.

0

精彩评论

暂无评论...
验证码 换一张
取 消