20inline namespace cpp20 {
60 if constexpr (std::is_const<T>::value) {
61 return os << type_descriptor<typename std::remove_const<T>::type>()
63 }
else if constexpr (std::is_lvalue_reference<T>::value) {
64 return os << type_descriptor<typename std::remove_reference<T>::type>()
66 }
else if constexpr (std::is_pointer<T>::value) {
67 using PointedT =
typename std::remove_pointer<T>::type;
68 if constexpr (std::is_function<PointedT>::value) {
70 typename std::invoke_result<PointedT>::type>()
73 return os << type_descriptor<PointedT>() <<
'*';
75 }
else if constexpr (std::is_array<T>::value) {
76 if constexpr (std::is_bounded_array<T>::value) {
77 return os << type_descriptor<typename std::remove_extent<T>::type>()
78 <<
'[' << std::extent<T>::value <<
']';
81 typename std::remove_extent<T>::type>() <<
"[]";
83 }
else if constexpr (std::is_function<T>::value) {
84 return os << type_descriptor<typename std::invoke_result<T>::type>()
86 }
else if constexpr (std::is_fundamental<T>::value) {
91 if constexpr (std::is_integral<T>::value) {
95 if constexpr (std::is_unsigned<T>::value) {
99 if constexpr (
sizeof(T) == 1) {
return os <<
"char"; }
100 else if constexpr (
sizeof(T) == 2) {
return os <<
"short int"; }
101 else if constexpr (
sizeof(T) == 4) {
return os <<
"int"; }
102 else if constexpr (
sizeof(T) == 8) {
return os <<
"long int"; }
103 else return error_unhandled_type<T>();
105 return error_unhandled_type<T>();
108 return error_unhandled_type<T>();
std::ostream & operator<<(std::ostream &os, type_descriptor< T > const &)
consteval T * error_unhandled_type()
Produce a compile-time failure for an "unhandled" type.
Encapsulate solution for Exercise 2-4.
Print (a limited set of) data-types.
Print (a limited set of) data-types.