Таким образом, основная идея состоит в том, что вы добавляете шаблон operator<<
, который смещает SFINAE в зависимости от типа возврата operator*
объекта, который он передал.Примерно так:
template <typename T, typename Expected>
using deref_to = std::is_same<std::decay_t<decltype(*std::declval<T>())>, Expected>;
template <typename T, typename = std::enable_if_t<deref_to<T, X>::value>>
std::ostream& operator<<(std::ostream &os, const T &foo) {
if(!foo)
os << "{}";
else
os << *foo;
return os;
}
Демо-версия , это работает даже для необработанных указателей.Не охватывает variant
или vector
, хотя это не должно быть слишком сложным для добавления.
Для обработки std::variant
, std::tuple
и std::pair
вы, вероятно, сделаетето же самое, только с std::get<X>
вместо operator*
.