Disambiguating calls to functions taking std::functions

自古美人都是妖i 提交于 2019-12-01 04:34:13

问题


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

回答1:


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++.




回答2:


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.



来源:https://stackoverflow.com/questions/4111647/disambiguating-calls-to-functions-taking-stdfunctions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!