Вопрос к знатокам.
Хочу сделать вывод названий типов используя typeid(T).name() для выражений которые «не умеют» выводить своё значение в std::ostream.
Пытаюсь делать вот так:
#include <iostream>
#include <typeinfo>
template <typename T, typename = std::ostream&>
struct can_be_streamed : std::false_type {};
template <typename T>
struct can_be_streamed<T, decltype(std::declval<std::ostream&>() << std::declval<T>())> : std::true_type {};
template <typename S, typename T>
typename std::enable_if<!can_be_streamed<T>::value, S&>::type operator<<(S &s, const T &t)
{
return s << "type:" << typeid(t).name();
}
class A {};
std::ostream& operator<<(std::ostream &s, const A &)
{
return s << "value:" /*<< ...*/;
}
class B {};
int main(void)
{
A a;
std::cout << a << std::endl;
B b;
std::cout << b << std::endl;
return EXIT_SUCCESS;
}
Есть несколько версий компиляторов и...
gcc 9.1.0 всё Ok.
clang 7.0.1 всё Ok.
А вот gcc 6.4.0 кричит:
v1.cpp: In substitution of 'template<class _CharT, class _Traits> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::error_code&) [with _CharT = char; _Traits = std::char_traits<char>]':
v1.cpp:8:66: recursively required by substitution of 'template<class S, class T> typename std::enable_if<(! can_be_streamed<T>::value), S&>::type operator<<(S&, const T&) [with S = std::basic_ostream<char>; T = char [8]]'
v1.cpp:8:66: required by substitution of 'template<class S, class T> typename std::enable_if<(! can_be_streamed<T>::value), S&>::type operator<<(S&, const T&) [with S = std::basic_ostream<char>; T = char [8]]'
v1.cpp:20:17: required from here
v1.cpp:8:66: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
struct can_be_streamed<T, decltype(std::declval<std::ostream&>() << std::declval<T>())> : std::true_type {};
Откуда рекурсия?
И что нужно подправить для gcc 6.4.0 что бы это починить?