Во-первых, исправьте свой ostreamable
класс. В настоящее время вашему классу требуется T
, чтобы его можно было копировать из 0
. Это не так для многих классов. Вместо этого следует использовать std::declval
для создания значения:
template <class O>
struct is_ostreamable {
template <class T>
static auto check(int) -> decltype(std::declval<std::ostream &>() << std::declval<T>(), std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
Здесь вносятся два изменения:
Операнд decltype
использует std::declval<T>()
для создать объект типа T
. std::declval<T>
- это (намеренно неопределенный) шаблон функции, который генерирует объект типа T
при использовании в неоцененном операнде (например, в операторе decltype
или sizeof
, noexcept
и т. Д. c. ) вне зависимости от заданной c сигнатуры конструкции (в вашем случае копирование-конструкция из 0
).
Параметр check
заменяется на int
. Инициализатор переменной value
вызывает check
с аргументом 0
, поэтому этот параметр int
гарантирует, что (int)
занимает место выше, чем (...)
в разрешении перегрузки, так что перегрузка true_type
выбирается при возможно.
Для манипуляторов функционального типа требуется специальная перегрузка (std::endl
, std::flush
, et c.):
using manip = std::ostream& (*)(std::ostream&);
CustomOutput& operator<<(manip m) {
os << m;
return *this;
}
К сожалению, нет никакого способа заставить шаблонную версию c поддерживать эту функцию. Это потому, что std::endl
является шаблоном функции:
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>& endl(td::basic_ostream<CharT, Traits>& os);
Для использования шаблона функции должны быть определены соответствующие аргументы шаблона. Невозможно вывести параметр type-template T
как шаблон generi c.
В любом случае, это, вероятно, единственная специальная перегрузка, которая вам понадобится.