构造std :: tuple时MSVC中的错误行为

时间:2015-10-22 03:37:14

标签: c++ c++11 visual-c++ compiler-errors c++14

我最近遇到(至少我认为是)MSVC ++ 2015中的错误行为(哦,什么新闻......)在尝试编译以下代码时(显而易见的简化):

#include <tuple>
#include <functional>

template<typename T>
using Func = std::function<void(T)>;

template<class...Ts>
class Foo
{
public:
    using Tuples = std::tuple<Func<Ts>...>;
    Foo(Tuples arg)
        : m_tuples(arg)
    {}
private:
    Tuples m_tuples;
};

struct Bar
{};

int main() {
    Foo<Bar> foo{std::make_tuple([](Bar) {})};
    return 0;
}

它适用于clang和gcc(支持c ++ 14的新版本和旧版本)但在MSVC ++ 2015中无法使用非常有趣的错误消息进行编译:

type_traits(1494): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
type_traits(1494): note: With the following template arguments:
type_traits(1494): note: '_Callable=std::tuple<std::function<void (Bar)>> &'
type_traits(1494): note: '_Types={Bar}'

第一个奇怪的行为在这里变得明显:为什么编译器试图将元组用作函数对象?进一步在堆栈中变得清晰: 它错误地实例化了元素构造函数

template< class... UTypes >
explicit constexpr tuple( UTypes&&... args );

而不是使用表现出正确行为的默认值 - 它甚至看起来MSVC的std实现中的额外SFINAE检查无法捕捉到这一点:

_Tuple_enable<tuple<tuple<std::function<void (Bar)>> &>, tuple<std::function<void (Bar)>>

这显然会导致从重载集中删除此构造函数,因为它只是归结为检查tuple<tuple<std::function<void (Bar)>> &>是否可转换为tuple<std::function<void (Bar)>>(AFAIK此转换不存在)。我不明白为什么它不会只使用默认的复制构造函数 - 或者我对标准错误的解释是什么?

由于clang和gcc都设法用正确的行为编译这段代码,我现在的问题是:这是微软的std实现或编译器错误的错误吗?作为参考,将构造函数更改为Foo(const Tuples& arg)会强制MSVC使用正确的元组构造函数(并且代码编译正常),而替代Foo(Tuples&& arg)Foo(Tuples& arg)也使用错误的元素构造函数。

完整的错误日志如下:

1>------ Build started: Project: TestProject, Configuration: Debug Win32 ------
1>  test.cpp
1>g:\misc\microsoft visual studio 14.0\vc\include\type_traits(1494): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1>  g:\misc\microsoft visual studio 14.0\vc\include\type_traits(1494): note: With the following template arguments:
1>  g:\misc\microsoft visual studio 14.0\vc\include\type_traits(1494): note: '_Callable=std::tuple<std::function<void (Bar)>> &'
1>  g:\misc\microsoft visual studio 14.0\vc\include\type_traits(1494): note: '_Types={Bar}'
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(210): note: see reference to function template instantiation 'void std::_Invoke_ret<_Rx,_Callable&,_Ty>(std::_Forced<_Rx,true>,_Callable &,_Ty &&)' being compiled
1>          with
1>          [
1>              _Rx=void,
1>              _Callable=_Decayed,
1>              _Ty=Bar
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(208): note: while compiling class template member function 'void std::_Func_impl<_Decayed,_Alloc,_Ret,Bar>::_Do_call(Bar &&)'
1>          with
1>          [
1>              _Alloc=std::allocator<int>,
1>              _Ret=void
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(136): note: see reference to class template instantiation 'std::_Func_impl<_Decayed,_Alloc,_Ret,Bar>' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<int>,
1>              _Ret=void
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(339): note: see reference to class template instantiation 'std::_Is_large<_Myimpl>' being compiled
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(318): note: see reference to function template instantiation 'void std::_Func_class<_Ret,Bar>::_Reset_alloc<_Ty,std::allocator<int>>(_Fx &&,const _Alloc &)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              _Ty=std::tuple<std::function<void (Bar)>>,
1>              _Fx=std::tuple<std::function<void (Bar)>>,
1>              _Alloc=std::allocator<int>
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(318): note: see reference to function template instantiation 'void std::_Func_class<_Ret,Bar>::_Reset_alloc<_Ty,std::allocator<int>>(_Fx &&,const _Alloc &)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              _Ty=std::tuple<std::function<void (Bar)>>,
1>              _Fx=std::tuple<std::function<void (Bar)>>,
1>              _Alloc=std::allocator<int>
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(484): note: see reference to function template instantiation 'void std::_Func_class<_Ret,Bar>::_Reset<std::tuple<std::function<void (Bar)>>>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              _Fx=std::tuple<std::function<void (Bar)>>
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\functional(484): note: see reference to function template instantiation 'void std::_Func_class<_Ret,Bar>::_Reset<std::tuple<std::function<void (Bar)>>>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              _Fx=std::tuple<std::function<void (Bar)>>
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\tuple(75): note: see reference to function template instantiation 'std::function<void (Bar)>::function<std::tuple<std::function<void (Bar)>>>(_Fx)' being compiled
1>          with
1>          [
1>              _Fx=std::tuple<std::function<void (Bar)>>
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\tuple(75): note: see reference to function template instantiation 'std::function<void (Bar)>::function<std::tuple<std::function<void (Bar)>>>(_Fx)' being compiled
1>          with
1>          [
1>              _Fx=std::tuple<std::function<void (Bar)>>
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\tuple(233): note: see reference to function template instantiation 'std::_Tuple_val<_This>::_Tuple_val<std::tuple<std::function<void (Bar)>>&>(_Other)' being compiled
1>          with
1>          [
1>              _This=std::function<void (Bar)>,
1>              _Other=std::tuple<std::function<void (Bar)>> &
1>          ]
1>  g:\misc\microsoft visual studio 14.0\vc\include\tuple(233): note: see reference to function template instantiation 'std::_Tuple_val<_This>::_Tuple_val<std::tuple<std::function<void (Bar)>>&>(_Other)' being compiled
1>          with
1>          [
1>              _This=std::function<void (Bar)>,
1>              _Other=std::tuple<std::function<void (Bar)>> &
1>          ]
1>  test.cpp(115): note: see reference to function template instantiation 'std::tuple<std::function<void (Bar)>>::tuple<std::tuple<std::function<void (Bar)>>&,,std::_Tuple_enable<std::tuple<>,std::tuple<>>::type>(_This2)' being compiled
1>          with
1>          [
1>              _This2=std::tuple<std::function<void (Bar)>> &
1>          ]
1>  test.cpp(115): note: see reference to function template instantiation 'std::tuple<std::function<void (Bar)>>::tuple<std::tuple<std::function<void (Bar)>>&,,std::_Tuple_enable<std::tuple<>,std::tuple<>>::type>(_This2)' being compiled
1>          with
1>          [
1>              _This2=std::tuple<std::function<void (Bar)>> &
1>          ]
1>  test.cpp(113): note: while compiling class template member function 'Foo<Bar>::Foo(std::tuple<std::function<void (Bar)>>)'
1>  test.cpp(134): note: see reference to function template instantiation 'Foo<Bar>::Foo(std::tuple<std::function<void (Bar)>>)' being compiled
1>  test.cpp(134): note: see reference to class template instantiation 'Foo<Bar>' being compiled
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

0 个答案:

没有答案