由于 std::function,构造函数重载中的歧义

Ambiguity in constructor overload because of std::function

我想对某些 class 的构造函数进行两次重载,如下所示:

foo(int, std::function<int(Tpoint, Tpoint)>);
foo(int, std::function<int(Tpoint, Tpoint, std::vector<Tpoint>)>);

调用时出现歧义问题。为什么?

foo<cv::Point> bar(2,[](cv::Point const& l, cv::Point const& r){
    return 5;
});

不清楚我是否需​​要这里的第一个构造函数,因为它只有 std::function.

的 2 个参数

编辑:

作为Lol4t0评论,它适用于另一个编译器。看来是VS.NET的问题。 Example 1 , Example 2

我正在使用 Microsoft Visual Studio 2013。任何人都可以复制吗?

MSVC 2013 std::function 只是一个 C++11 std::function,没有来自(如果我没记错的话)缺陷报告的附加功能。

此附加功能是 template<class F> function(F&&) 构造函数类似于 SFINAE,仅限于类型 F,因此 function 实际上可以从该类型构造。 (该标准不强制要求基于 SFINAE 的实现)

实际上,std::function 有一个 "try constructing from anything" 构造函数。当它失败时,它对于重载解析来说失败得太晚了。至少在 MSVC2013 中。所以你的两个 std::function 看起来都是有效的重载。

我相信 2015 的最新版本 std::function 具有 有限的 能力来完成您请求的过载。

在 2013 年,您可以做一个可能有效的解决方法,但这很痛苦。

首先,了解如何重载函数对象集。然后,创建一个函数对象 F 和另一个采用 Tpoint, Tpoint 和 returns some_special_tag_type 的函数对象的重载集。现在,将 Tpoint, Tpoint 传递给该重载集,并跟踪 return 类型是否为 some_special_tag_type。从 foo(int, F&&) 重载到 foo_impl(tag_1, int, std::function<blah_1>)foo_impl(tag_2, int, std::function<blah_2>).

的此决定的标记分派

升级到 MSVC2015 或不依赖重载可能更容易。

请注意,如果您重载 return 类型而不是参数类型,则此技术实际上是可行的。这很难,因为即使 MSVC2015 也没有 "expression SFINAE",这削弱了这种元编程。