标准是否要求 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。谁在此处的另一个答案的评论线程中解决了这个问题。