Does the standard require std::tuple_size to be SF

2019-02-21 08:55发布

Edit append: The question title was "do Visual Studio compiler or Clang have incorrect behavior"- but that have been changed.

So I add here that clang and gcc compiles it the way I intended, but VS does not.

I have the following code:

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;
}

and I get an compiler error:

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>          ]

That is because the following code in 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.");   
};

make the substitution failure into a hard failure- making the SFINAE SFIAE

If I remove

static_assert(_Always_false<_Tuple>::value, "The C++ Standard doesn't define tuple_size for this type.");

it works.

Is the code strecthing the c++ standard rules? Or is Microsoft in the wrong?

标签: c++ c++14 sfinae
3条回答
萌系小妹纸
2楼-- · 2019-02-21 09:17

The standard mandates that tuple_size not be SFINAE friendly, but this is considered by many to be a defect, and looks on-track to be fixed in C++17.

It is required that all specializations (which in standard-speak for "template instantiations") of tuple_size basically be std::integral_constant<size_t, ?> or inherit from it. (It leaves some freedom to the compiler)

If the primary template isn't defined, then it doesn't violate that. But if the primary template is defined to be an empty struct (or similar), then that empty struct is a template instance (which the standard calls a "specialization") that is not essentially std::integral_constant<size_t, ?>.

By my reading, it would be legal for the primary template (the "failure" case) to be std::integral_constant<size_t, 42> or any other constant. Useless and evil, but legal. But being an empty struct violates the standard.

However, the arguments about changing this to mandate an empty struct are about wording, and not about if it is a good idea.

Thanks to @T.C. who solved this in a comment thread on another answer here.

查看更多
别忘想泡老子
3楼-- · 2019-02-21 09:18

Could something like this perhaps work with some modifications?

template<typename S, typename T,    typename   tuple_element<0,decltype(T::children)>::type >
    S& operator<<(S& s, const T& t)
查看更多
太酷不给撩
4楼-- · 2019-02-21 09:20

N4140 20.4.1 describes tuple_size's non-specialized version as:

template <class T> class tuple_size; // undefined

By providing a definition, the MSVC lib has violated the standard.

You should realize however, that your question is not about the compilers involved, but rather the standard library implementations.

查看更多
登录 后发表回答