我最近遇到(至少我认为是)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 ==========