std::function<...> 上的重载
给出以下代码:-
#include <algorithm>
#include <iostream>
#include <functional>
#include <string>
void func(std::function<void(void)> param)
{
param();
}
void func(std::function<void(int)> param)
{
param(5);
}
int main(int argc, char* argv[])
{
func([] () { std::cout << "void(void)" << std::endl; });
func([] (int i) { std::cout << "void(int): " << i << std::endl; });
std::string line;
std::getline(std::cin, line);
return 0;
}
VS2010 编译错误:-
CppTest.cpp(18): error C2668: 'func' : ambiguous call to overloaded function
1> CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (int)
1> ]
1> CppTest.cpp(6): or 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (void)
1> ]
1> while trying to match the argument list '(`anonymous-namespace'::<lambda0>)'
1>CppTest.cpp(19): error C2668: 'func' : ambiguous call to overloaded function
1> CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (int)
1> ]
1> CppTest.cpp(6): or 'void func(std::tr1::function<_Fty>)'
1> with
1> [
1> _Fty=void (void)
1> ]
1> while trying to match the argument list '(`anonymous-namespace'::<lambda1>)'
g++-4.5 编译错误
program2.cpp: In function ‘int main(int, char**)’:
program2.cpp:18:68: error: call of overloaded ‘func(main(int, char**)::<lambda()>)’ is ambiguous
program2.cpp:6:10: note: candidates are: void func(std::function<void()>)
program2.cpp:11:10: note: void func(std::function<void(int)>)
program2.cpp:19:79: error: call of overloaded ‘func(main(int, char**)::<lambda(int)>)’ is ambiguous
program2.cpp:6:10: note: candidates are: void func(std::function<void()>)
program2.cpp:11:10: note: void func(std::function<void(int)>)
所以看来编译器无法弄清楚 lambda [] () -> void 只能赋值给 std::function
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是应该发生的。
std::function
有一个构造函数模板,可以接受任何类型的参数。编译器直到选择并实例化构造函数模板之后才能知道它将遇到错误,并且它必须能够选择函数的重载才能执行此操作。最直接的修复方法是使用强制转换或显式构造正确类型的
std::function
对象:如果您有一个支持 captureless-lambda-to-function-pointer 转换的编译器,并且你的 lambda 没有捕获任何内容,你可以使用原始函数指针:(
看起来你正在使用 Visual C++ 2010,它不支持此转换。直到 Visual Studio 2010 发布之前,该转换才添加到规范中晚了添加它。)
为了更详细地解释这个问题,请考虑以下内容:
这基本上就是有问题的
std::function
构造函数的样子:您可以使用任何参数调用它,即使该参数没有意义并且会在其他地方导致错误。例如,function f(42);
将使用U = int
调用此构造函数模板。在您的具体示例中,编译器在重载解析期间找到两个候选函数:
参数类型(我们将其称为
F
的一些无法说出的 lambda 类型名称)与其中任何一个都不完全匹配,因此编译器开始查看它可以对F
进行哪些转换,以尝试使其与这些候选函数之一匹配。当寻找转换时,它会找到前面提到的构造函数模板。此时编译器看到的只是它可以调用任一函数,因为
F
转换为std::function
U = F
并且U 的转换构造函数将
F
转换为std::function
= F。在您的示例中,显然只有其中之一会成功且不会出现错误,但在一般情况下并非如此。编译器不能做任何进一步的事情。它必须报告歧义并失败。它无法选择其中一个,因为两种转换都同样好,并且两种重载都不比另一种更好。
This is supposed to happen.
std::function
has a constructor template that can take an argument of any type. The compiler can't know until after a constructor template is selected and instantiated that it's going to run into errors, and it has to be able to select an overload of your function before it can do that.The most straightforward fix is to use a cast or to explicitly construct a
std::function
object of the correct type:If you have a compiler that supports the captureless-lambda-to-function-pointer conversion and your lambda doesn't capture anything, you can use raw function pointers:
(It looks like you are using Visual C++ 2010, which does not support this conversion. The conversion was not added to the specification until just before Visual Studio 2010 shipped, too late to add it in.)
To explain the problem in a bit more detail, consider the following:
This is basically what the
std::function
constructor in question looks like: You can call it with any argument, even if the argument doesn't make sense and would cause an error somewhere else. For example,function<int()> f(42);
would invoke this constructor template withU = int
.In your specific example, the compiler finds two candidate functions during overload resolution:
The argument type, some unutterable lambda type name that we will refer to as
F
, doesn't match either of these exactly, so the compiler starts looking at what conversions it can do toF
to try and make it match one of these candidate functions. When looking for conversions, it finds the aforementioned constructor template.All the compiler sees at this point is that it can call either function because
F
tostd::function<void(void)>
using its converting constructor withU = F
andF
tostd::function<void(int)>
using its converting constructor withU = F
.In your example it is obvious that only one of these will succeed without error, but in the general case that isn't true. The compiler can't do anything further. It has to report the ambiguity and fail. It can't pick one because both conversions are equally good and neither overload is better than the other.