Стандарт требует, чтобы std:: tuple_size был SFINAE-дружественным?

Изменить добавление: Заголовок вопроса: "У компилятора Visual Studio или Clang есть неправильное поведение", но это было изменено.

Поэтому я добавляю здесь, что 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  &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.");

он работает.

Является ли код исправлением стандартных правил С++? Или Microsoft ошибается?

Ответы

Ответ 1

Стандартные мандаты, которые tuple_size не, являются SFINAE дружественными, но это считается многими дефектами и выглядит на дорожке, которая будет исправлена ​​в С++ 17.

Требуется, чтобы все специализации (которые в стандартном выражении для "экземпляров шаблонов" ) tuple_size в основном были std::integral_constant<size_t, ?> или наследованы от него. (Он оставляет некоторую свободу компилятору)

Если первичный шаблон не определен, он не нарушает этого. Но если основной шаблон определяется как пустая структура (или аналогичная), то эта пустая структура является экземпляром шаблона (который стандарт вызывает "специализацию" ), который по существу не является std::integral_constant<size_t, ?>.

По моим показаниям, основной шаблон ( "случай отказа" ) был бы законным std::integral_constant<size_t, 42> или любой другой константой. Бесполезные и злые, но законные. Но наличие пустой структуры нарушает стандарт.

Однако аргументы об изменении этого мандата на пустую структуру составляют формулировку, а не о том, является ли это хорошей идеей.

Благодаря @T.C. кто решил это в комментариях на другой ответ здесь.

Ответ 2

N4140 20.4.1 описывает tuple_size неспециализированную версию как:

template <class T> class tuple_size; // undefined

Предоставляя определение, MSVC lib нарушил стандарт.

Однако вы должны понимать, что ваш вопрос касается не компиляторов, а стандартных реализаций библиотек.

Ответ 3

Может ли что-то подобное работать с некоторыми изменениями?

template<typename S, typename T,    typename   tuple_element<0,decltype(T::children)>::type >
    S& operator<<(S& s, const T& t)