2015-07-21 115 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會有自動返回類型演繹,我的生活將會變得如此簡單... –