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

查看:19
本文介绍了重载 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,而 lambda [] (int) -> void 只能分配给 std::function.这是应该发生的还是编译器的一个缺陷?

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 构造函数的样子:您可以使用任何参数调用它,即使该参数没有意义并且会在其他地方导致错误.例如,functionf(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/li>
  • 它可以使用U = F的转换构造函数将F转换为std::function.
  • 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天全站免登陆