标准是否要求 std::tuple_size 为 SFINAE-friendly?
Does the standard require std::tuple_size to be SFINAE-friendly?
编辑追加:
问题标题是 "do Visual Studio compiler or Clang have incorrect behavior"- 但已更改。
所以我在这里补充一下,clang 和 gcc 按照我想要的方式编译它,但 VS 没有。
我有以下代码:
template<typename S, typename T, std::size_t... I>
void
print_tuple_like(S& s, const T& t, std::index_sequence<I...>)
{
void* unused[] = { &(s << std::get<I>(t))... };
}
template<typename S, typename T,
std::size_t N = std::tuple_size<decltype(T::children)>::value>
S& operator<<(S& s, const T& t)
{
print_tuple_like(s, t.children, std::make_index_sequence<N>{});
return s;
}
我得到一个编译器错误:
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\utility(313): error C2338: The C++ Standard doesn't define tuple_size for this type.
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(36): note: see reference to class template instantiation 'std::tuple_size<unknown-type>' being compiled
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(43): note: see reference to function template instantiation 'void print_tuple_like<S,std::tuple<Signature::A,Signature::B>,0,1>(S &,const T &,std::integer_sequence<_Ty,0,1>)' being compiled
1> with
1> [
1> S=std::ostream,
1> T=std::tuple<Signature::A,Signature::B>,
1> _Ty=size_t
1> ]
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(50): note: see reference to function template instantiation 'S &operator <<<std::ostream,Signature,2>(S &,const T &)' being compiled
1> with
1> [
1> S=std::ostream,
1> T=Signature
1> ]
那是因为visual studio中有如下代码:
// TEMPLATE STRUCT tuple_size
template<class _Tuple>
struct tuple_size { // size of non-tuple
static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type.");
};
将替换失败变为硬失败-使SFINAE SFIAE
如果我删除
static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type.");
有效。
代码是否符合 c++ 标准规则?
还是微软错了?
N4140 20.4.1 将 tuple_size
的非专用版本描述为:
template <class T> class tuple_size; // undefined
通过提供定义,MSVC 库违反了标准。
但是您应该意识到,您的问题不是关于所涉及的编译器,而是关于标准库实现。
这样的东西是否可以进行一些修改?
template<typename S, typename T, typename tuple_element<0,decltype(T::children)>::type >
S& operator<<(S& s, const T& t)
标准要求 tuple_size
不 SFINAE 友好,但 this is considered by many to be a defect, and looks on-track to be fixed in C++17.
要求 tuple_size
的所有特化(在标准中为 "template instantiations")基本上是 std::integral_constant<size_t, ?>
或从它继承。 (它给编译器留下了一些自由)
如果未定义主模板,则不违反该规定。但是,如果主模板被定义为一个空结构(或类似结构),那么该空结构就是一个模板实例(标准称为 "specialization"),本质上不是 std::integral_constant<size_t, ?>
.
根据我的阅读,主模板("failure" 情况)是 std::integral_constant<size_t, 42>
或任何其他常量是合法的。无用且邪恶,但合法。但是作为一个空结构违反了标准。
但是,关于将此更改为强制使用空结构的争论是关于措辞,而不是关于它是否是个好主意。
感谢@T.C。谁在此处的另一个答案的评论线程中解决了这个问题。
编辑追加: 问题标题是 "do Visual Studio compiler or Clang have incorrect behavior"- 但已更改。
所以我在这里补充一下,clang 和 gcc 按照我想要的方式编译它,但 VS 没有。
我有以下代码:
template<typename S, typename T, std::size_t... I>
void
print_tuple_like(S& s, const T& t, std::index_sequence<I...>)
{
void* unused[] = { &(s << std::get<I>(t))... };
}
template<typename S, typename T,
std::size_t N = std::tuple_size<decltype(T::children)>::value>
S& operator<<(S& s, const T& t)
{
print_tuple_like(s, t.children, std::make_index_sequence<N>{});
return s;
}
我得到一个编译器错误:
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\utility(313): error C2338: The C++ Standard doesn't define tuple_size for this type.
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(36): note: see reference to class template instantiation 'std::tuple_size<unknown-type>' being compiled
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(43): note: see reference to function template instantiation 'void print_tuple_like<S,std::tuple<Signature::A,Signature::B>,0,1>(S &,const T &,std::integer_sequence<_Ty,0,1>)' being compiled
1> with
1> [
1> S=std::ostream,
1> T=std::tuple<Signature::A,Signature::B>,
1> _Ty=size_t
1> ]
1> c:\users\jonas\documents\visual studio 2015\projects\consoleapplication7\consoleapplication7\consoleapplication7.cpp(50): note: see reference to function template instantiation 'S &operator <<<std::ostream,Signature,2>(S &,const T &)' being compiled
1> with
1> [
1> S=std::ostream,
1> T=Signature
1> ]
那是因为visual studio中有如下代码:
// TEMPLATE STRUCT tuple_size
template<class _Tuple>
struct tuple_size { // size of non-tuple
static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type.");
};
将替换失败变为硬失败-使SFINAE SFIAE
如果我删除
static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type.");
有效。
代码是否符合 c++ 标准规则? 还是微软错了?
N4140 20.4.1 将 tuple_size
的非专用版本描述为:
template <class T> class tuple_size; // undefined
通过提供定义,MSVC 库违反了标准。
但是您应该意识到,您的问题不是关于所涉及的编译器,而是关于标准库实现。
这样的东西是否可以进行一些修改?
template<typename S, typename T, typename tuple_element<0,decltype(T::children)>::type >
S& operator<<(S& s, const T& t)
标准要求 tuple_size
不 SFINAE 友好,但 this is considered by many to be a defect, and looks on-track to be fixed in C++17.
要求 tuple_size
的所有特化(在标准中为 "template instantiations")基本上是 std::integral_constant<size_t, ?>
或从它继承。 (它给编译器留下了一些自由)
如果未定义主模板,则不违反该规定。但是,如果主模板被定义为一个空结构(或类似结构),那么该空结构就是一个模板实例(标准称为 "specialization"),本质上不是 std::integral_constant<size_t, ?>
.
根据我的阅读,主模板("failure" 情况)是 std::integral_constant<size_t, 42>
或任何其他常量是合法的。无用且邪恶,但合法。但是作为一个空结构违反了标准。
但是,关于将此更改为强制使用空结构的争论是关于措辞,而不是关于它是否是个好主意。
感谢@T.C。谁在此处的另一个答案的评论线程中解决了这个问题。