在std :: function< ...>上重载 [英] Overloading on std::function<...>

查看:81
本文介绍了在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中的编译错误:-

Compile error from 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编译错误

Compile error from 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< void(void)>和lambda [](int)- > void只能分配给std :: function< void(int)>.是应该发生这种情况还是只是编译器中的不足?

So it seems the compiler can't figure out that a lambda [] () -> void can only be assigned to a std::function<void(void)>, and a lambda [] (int) -> void can only be assigned to a std::function<void(int)>. Is this supposed to happen or just a deficiency in the compilers?

推荐答案

这是应该发生的还是只是编译器中的不足?

Is this supposed to happen or just a deficiency in the compilers?

这应该发生. std::function具有一个构造函数模板,该模板可以接受任何类型的参数.直到选择了构造函数模板并将其实例化后,编译器才知道它会出错,并且编译器必须能够选择函数的重载才能做到这一点.

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.

最直接的解决方法是使用类型转换或显式构造正确类型的std::function对象:

The most straightforward fix is to use a cast or to explicitly construct a std::function object of the correct type:

func(std::function<void()>([](){}));
func(std::function<void(int)>([](int){}));

如果您的编译器支持不捕获lambda到函数指针的转换,而您的lambda不捕获任何东西,则可以使用原始函数指针:

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:

void func(void (*param)()) { }
void func(void (*param)(int)) { }

(您似乎使用的是Visual C ++ 2010,它不支持此转换.直到Visual Studio 2010发行之前,该转换才添加到规范中,已经太晚了,无法将其添加进来.)

(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:

template <typename T>
struct function {

    template <typename U>
    function(U f) { }
};

这基本上是所讨论的std::function构造函数的样子:您可以使用任何参数调用它,即使该参数没有意义并且会在其他地方引起错误.例如,function<int()> f(42);将使用U = int调用此构造函数模板.

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 with U = int.

在您的特定示例中,编译器在重载解析期间找到了两个候选函数:

In your specific example, the compiler finds two candidate functions during overload resolution:

void func(std::function<void(void)>)
void func(std::function<void(int)>)

参数类型(我们将称为F的某些不可言喻的lambda类型名称)与上述两个都不完全匹配,因此编译器开始研究它可以对F进行哪些转换以尝试进行转换它与这些候选功能之一匹配.在寻找转换时,它会找到上述的构造器模板.

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 to F 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

  • 使用U = F
  • 的转换构造函数,可以将F转换为std::function<void(void)>
  • 它可以使用U = F的转换构造函数将F转换为std::function<void(int)>.
  • it can convert F to std::function<void(void)> using its converting constructor with U = F and
  • it can convert F to std::function<void(int)> using its converting constructor with U = 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.

这篇关于在std :: function&lt; ...&gt;上重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆