visual studio 2015 无法编译有效代码(标准函数错误?)

Valid code fail to be compiled by visual studio 2015 (std function bug?)

我最近一直在使用 c++11 编写一些代码。这段代码在 GCC 和 Clang 中运行良好,我在我的项目中广泛使用了它。现在,我需要让它在 MSVC 中工作。我需要的所有 c++11 功能都标记为是。但是,此代码示例只是拒绝构建。我试图修复错误,但我还没有找到解决方案。这是样本:

#include <functional>
#include <iostream>
#include <type_traits>

template<typename T>
struct Provider final {
    Provider() = delete;
    Provider(const Provider& other) : _callback{ other._callback } {}
    Provider(Provider&& other) : _callback{ std::move(other._callback) } {}

    Provider& operator=(Provider&& other) {
        std::swap(other._callback, _callback);
        return *this;
    }

    Provider& operator=(const Provider& other) {
        _callback = other._callback;
        return *this;
    }

    template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
    Provider<T>& operator=(Provider<U>&& other) {
        std::swap(other._callback, _callback);
        return *this;
    }

    template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
    Provider<T>& operator=(const Provider<U>& other) {
        _callback = other._callback;
        return *this;
    }

    template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
    Provider(const Provider<U>& other) : _callback{ other._callback } {}

    template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
    Provider(Provider<U>&& other) : _callback{ std::move(other._callback) } {}

    template<typename U, typename = typename std::enable_if<std::is_constructible<std::function<T()>, U>::value>::type>
    Provider(U callback) : _callback{ callback } {}

    template<typename = typename std::enable_if<!std::is_constructible<std::function<T()>, T>::value, T>::type>
    Provider(T value) : _callback{[=] { return value; }} {}

    template<typename U>
    friend struct Provider;

    T operator()() const {
        return _callback();
    }

private:
    std::function<T()> _callback;
};

template<typename T>
void doSomething(Provider<T> p) {
    std::cout << "My value is:" << p() << std::endl;
}

int main()
{
    Provider<int> p1 = 9;
    Provider<double> p2 = [] { return 9.4; };
    Provider<unsigned int> p3{9};
    Provider<float> p4{[]{ return 9.4f; }};

    doSomething<unsigned int>(5);
    doSomething<float>([] { return 9.5f; });
    doSomething<int>(p1);
    doSomething<double>(p2);

    return 0;
}

应该输出这个:

My value is:5
My value is:9.5
My value is:9
My value is:9.4

但是,编译器输出向我抛出这个:

1>------ Build started: Project: test1, Configuration: Debug Win32 ------
1>  test1.cpp
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1501): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1501): note: With the following template arguments:
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1501): note: '_Callable=_Decayed &'
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\type_traits(1501): note: '_Types={}'
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(210): note: see reference to function template instantiation '_Rx std::_Invoke_ret<_Rx,_Callable&>(std::_Forced<_Rx,false>,_Callable &)' being compiled
1>          with
1>          [
1>              _Rx=unsigned int,
1>              _Callable=_Decayed
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(208): note: while compiling class template member function 'unsigned int std::_Func_impl<_Decayed,_Alloc,_Ret>::_Do_call(void)'
1>          with
1>          [
1>              _Alloc=std::allocator<int>,
1>              _Ret=unsigned int
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(136): note: see reference to class template instantiation 'std::_Func_impl<_Decayed,_Alloc,_Ret>' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<int>,
1>              _Ret=unsigned int
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(339): note: see reference to class template instantiation 'std::_Is_large<_Myimpl>' being compiled
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(318): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset_alloc<_Ty,std::allocator<_Ty>>(_Fx &&,const _Alloc &)' being compiled
1>          with
1>          [
1>              _Ret=unsigned int,
1>              _Ty=int,
1>              _Fx=int,
1>              _Alloc=std::allocator<int>
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(318): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset_alloc<_Ty,std::allocator<_Ty>>(_Fx &&,const _Alloc &)' being compiled
1>          with
1>          [
1>              _Ret=unsigned int,
1>              _Ty=int,
1>              _Fx=int,
1>              _Alloc=std::allocator<int>
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(484): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset<int>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Ret=unsigned int,
1>              _Fx=int
1>          ]
1>  c:\program files (x86)\microsoft visual studio 14.0\vc\include\functional(484): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset<int>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Ret=unsigned int,
1>              _Fx=int
1>          ]
1>  c:\users\master\documents\visual studio 2015\projects\test1\test1\test1.cpp(43): note: see reference to function template instantiation 'std::function<T (void)>::function<U>(_Fx)' being compiled
1>          with
1>          [
1>              T=unsigned int,
1>              U=int,
1>              _Fx=int
1>          ]
1>  c:\users\master\documents\visual studio 2015\projects\test1\test1\test1.cpp(43): note: see reference to function template instantiation 'std::function<T (void)>::function<U>(_Fx)' being compiled
1>          with
1>          [
1>              T=unsigned int,
1>              U=int,
1>              _Fx=int
1>          ]
1>  c:\users\master\documents\visual studio 2015\projects\test1\test1\test1.cpp(68): note: see reference to function template instantiation 'Provider<unsigned int>::Provider<int,void>(U)' being compiled
1>          with
1>          [
1>              U=int
1>          ]
1>  c:\users\master\documents\visual studio 2015\projects\test1\test1\test1.cpp(68): note: see reference to function template instantiation 'Provider<unsigned int>::Provider<int,void>(U)' being compiled
1>          with
1>          [
1>              U=int
1>          ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

ideone上完全相同的代码,编译执行成功: https://ideone.com/aANd04

提前致谢!

VS 2015(尚)不支持表达式 SFINAE,因此您不能在 std::function 上使用 std::is_constructible。 (请注意,严格来说这是一个 C++14 功能;C++11 std::function 构造不支持 SFINAE。)

来自http://blogs.msdn.com/b/vcblog/archive/2015/04/29/c-11-14-17-features-in-vs-2015-rc.aspx

We're planning to start implementing Expression SFINAE in the compiler immediately after 2015 RTM, and we're planning to deliver it in an Update to 2015, supported for production use. (But not necessarily 2015 Update 1. It might take longer.)