由于std :: function

时间:2016-02-12 14:01:42

标签: c++ c++11 visual-studio-2013 std-function compiler-bug

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

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 1Example 2

我正在使用Microsoft Visual Studio 2013.任何人都可以重现吗?

1 个答案:

答案 0 :(得分:2)

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

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

实际上,std::function有一个“尝试从任何东西构建”的构造函数。当它失败时,它的失败太晚,无法解决重载问题。至少在MSVC2013中。所以你的std::function看起来都是有效的重载。

我相信2015年的最新版本有一个std::function 有限能够执行您要求的重载。

2013年,您可以采取可行的解决方法,但这很痛苦。

首先,学习如何进行函数对象的重载集。然后,创建一个函数对象F的重载集和另一个取Tpoint, Tpoint并返回some_special_tag_type的函数对象。现在,将Tpoint, Tpoint传递给该重载集,并跟踪返回类型是否为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可能更容易,或者不依赖于重载。

请注意,如果您在返回类型上重载,而不是在参数类型上重载,则此技术实际上是可行的。这很难,因为即使是MSVC2015也没有“表达SFINAE”,这会削弱这种元编程。