Вы можете сделать это:
template <typename T, unsigned int N>
std::ostream & operator<<(std::ostream & os, const T (&arr)[N])
{
// ..
return os;
}
Конечно, это работает только для массивов времени компиляции. Обратите внимание, что вам не разрешено создавать экземпляры этого шаблона, если T
является встроенным типом или типом в пространстве имен std
!
Вероятно, лучше сделать это встроенным, если это возможно, так как вы будете вызывать отдельную реализацию для каждого N
. (У симпатичного принтера есть пример этого.)
Тем не менее, вы заметите, что общий шаблон вносит неоднозначность, поскольку os << "Hello"
теперь имеет две возможные перегрузки: шаблон соответствует const char (&)[6]
и (не шаблонная) перегрузка для распада на указатель const char *
, которые оба имеют идентичные последовательности преобразования. Мы можем решить эту проблему, отключив нашу перегрузку для массивов символов:
#include <ostream>
#include <type_traits>
template <typename T, unsigned int N>
typename std::enable_if<!std::is_same<T, char>::value, std::ostream &>::type
operator<<(std::ostream & os, const T (&arr)[N])
{
// ..
return os;
}
На самом деле, чтобы быть еще более общим, вы можете также сделать параметры шаблона параметров basic_ostream
:
template <typename T, unsigned int N, typename CTy, typename CTr>
typename std::enable_if<!std::is_same<T, char>::value,
std::basic_ostream<CTy, CTr> &>::type
operator<<(std::basic_ostream<CTy, CTr> & os, const T (&arr)[N])
{
// ..
return os;
}
Ввиду того, что T
должен быть пользовательским типом, вы можете даже заменить is_same<T, char>
на is_fundamental<T>
, чтобы получить немного больше проверки (но пользователи по-прежнему не должны использовать это для массивов стандартной библиотеки типов).