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?
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 bestd::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.