2015-07-21 108 views
1

我们希望使用std::async将作业启动到应用程序范围的线程池。为此,我们在我们自己的命名空间x中实施了两个std::async签名的包装。因此x::async(f, a, b)会将f(a,b)启动到一个线程池队列中。而x::async(std::launch::deferred, f, a, b)只会转发到std::async。这是一个方便的一站式商店,用于启动工作,而不必停下来思考要使用哪些功能。模板重载分辨率奇怪VS2013

当实现两个重载(带和不带启动策略)时,我遇到了错误的模板重载问题,导致编译时错误。我尝试了GCC 5.2.0中的代码,它编译得很好,导致我怀疑Visual Studio的bug(不会是第一个)。

下面是一个最小的示例,显示我遇到的错误。

#include <future> 
#include <utility> 
#include <type_traits> 

namespace x { 
    template< class Function, class... Args> 
    std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> async(Function&& f, Args&&... args){ 
     return std::async(std::launch::async, std::forward<Function>(f), std::forward<Args>(args)...); 
    } 

    template< class Function, class... Args> 
    std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> async(std::launch policy, Function&& f, Args&&... args){ 
     return std::async(policy, std::forward<Function>(f), std::forward<Args>(args)...); 
    } 
} 

int main(){ 
    std::function<void(std::size_t, std::size_t)> f = [](std::size_t a, std::size_t b) { }; 

    auto ftr = x::async(f, 2, 3); 
} 

在这里,而不是指派给我的线程池我只是期待std::async为简单起见,它仍然显示了同样的错误。

我得到的编译错误是:

vc\include\xrefwrap(58): error C2064: term does not evaluate to a function taking 1 
    arguments 
    vc\include\xrefwrap(118) : see reference to class template instantiation 
    'std::_Result_of<_Fty,int>' being compiled 
    with 
    [ 
     _Fty=int 
    ] 
    project\source.cpp(18) : see reference to class template instantiation 
    'std::result_of<int (int)>' being compiled 

这表明,它实际上是解决呼叫:x::async(f,2,3)x::async(policy, function, args...)过载和转换std::functionstd::launch并采取2作为调用参数3一个可调用的函数...通过发布策略评论超载,代码编译得很好,进一步加强了我的看法,即它是一个visual studio bug。

我要求另一对眼睛在我提交给微软之前验证它不是我的错误代码。

+0

@Columbo我想我能做到这一点作为解决方法,但我想匹配签名与[std :: async](http://en.cppreference.com/w/cpp/thread/async)。无论如何,问题依然存在:它应该起作用吗?这是一个编译器错误? –

+0

@Columbo有趣的是,当您的提案(在单独工作时)应用于我们的代码时,会导致'致命错误C1001:编译器中发生了内部错误',然后编译器会适当地前倾。 –

回答

1

这似乎是由于Visual Studio没有实现作为C++ 14一部分的N3462(SFINAE友好的result_of)。这是有益的,通过使用std::enable_if研究Studio如何可视化的实现的解决此问题std::async作品:

template <class Function, class... Args> 
std::future<std::result_of_t< 
    std::enable_if_t< 
     ! std::is_same<std::decay_t<Function>, std::launch>::value, 
     std::decay_t<Function> 
    >(std::decay_t<Args>...) 
>> async(Function&& f, Args&&... args) { 
    return std::async(std::launch::async, std::forward<Function>(f), std::forward<Args>(args)...); 
} 

template <class Policy, class Function, class... Args> 
std::future<std::result_of_t< 
    std::enable_if_t< 
     std::is_same<Policy, std::launch>::value, 
     std::decay_t<Function> 
    >(std::decay_t<Args>...) 
>> async(Policy policy, Function&& f, Args&&... args) { 
    return std::async(policy, std::forward<Function>(f), std::forward<Args>(args)...); 
} 

您也可避免result_of完全使用decltype

template <class Function, class... Args> 
auto async(Function&& f, Args&&... args) 
-> std::future<decltype(std::forward<Function>(f)(std::forward<Args>(args)...))> { 
    return std::async(std::launch::async, std::forward<Function>(f), std::forward<Args>(args)...); 
} 

template <class Function, class... Args> 
auto async(std::launch policy, Function&& f, Args&&... args) 
-> std::future<decltype(std::forward<Function>(f)(std::forward<Args>(args)...))> { 
    return std::async(policy, std::forward<Function>(f), std::forward<Args>(args)...); 
} 
+0

'decltype'解决方法奏效。如果VS2013会有自动返回类型演绎,我的生活将会变得如此简单... –