模板重载分辨率奇怪VS2013

时间:2015-07-21 09:11:03

标签: c++ templates visual-studio-2013 c++14

我们希望使用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 ...通过使用启动策略注释掉过载,代码编译得很好,进一步加强了我的信念,即它是一个视觉工作室错误。

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

1 个答案:

答案 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)...);
}