我们希望使用std::async
将作业启动到应用程序范围的线程池。为此,我们在我们自己的命名空间std::async
中为两个x
签名实现了两个包装器。因此x::async(f, a, b)
会将f(a,b)
启动到线程池队列中。而x::async(std::launch::deferred, f, a, b)
只会转发到std::async
。这是一个方便的一站式服务,无需停下来思考使用哪些功能就可以开展工作。
当实现两个重载(有和没有启动策略)时,我遇到了错误的模板重载被解决的问题,导致编译时错误。我在GCC 5.2.0中尝试了代码并且编译得很好,导致我怀疑Visual Studio错误(不会是第一个)。
下面是一个显示我遇到的错误的最小示例。
#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::function
转换为std::launch
并将2
作为可调用函数调用使用参数3
...通过使用启动策略注释掉过载,代码编译得很好,进一步加强了我的信念,即它是一个视觉工作室错误。
我要求另外一双眼睛在我提交给微软之前验证它不是我的错误代码。
答案 0 :(得分:1)
这似乎是由于Visual Studio没有实现N3462(SFINAE友好result_of
),这是C ++ 14的一部分。通过使用std::async
来检查Visual Studio的std::enable_if
实现如何解决此问题是有益的:
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)...);
}