Skip to content

Instantly share code, notes, and snippets.

@ArnCarveris
Last active January 11, 2024 14:52
Show Gist options
  • Save ArnCarveris/e68fdf559fce1d634ebbec00fd5e8414 to your computer and use it in GitHub Desktop.
Save ArnCarveris/e68fdf559fce1d634ebbec00fd5e8414 to your computer and use it in GitHub Desktop.
has_ostream_operator for C++98
#include <iostream>
#include <typeinfo>
namespace detail {
namespace has_ostream_operator_impl {
//!Typedef a char array of size one.
typedef char no;
//! Typedef a char array of size two.
typedef char yes[2];
//! A fallback struct which can create itself
// from any object of any type.
struct fallback {
template<typename T>
fallback(const T &);
};
//! Declare a dummy << operator which operates on
// any fallback object.
no operator << (std::ostream const &, fallback const &);
//! If the class does have an << operator overloaded,
// then the return type of invoking it has to be a
// std::ostream &. In that case, this function will
// be invoked.
yes & test(std::ostream &);
//! If the class did not have an << operator overloaded
// to begin with, it will use the global << operator
// defined in this namespace. It will convert itself into
// fallback object and then invoke this function. In this
// case, the return type in no.
no & test(no);
template<typename T>
struct has_ostream_operator {
static std::ostream &s;
static T &t;
// compiler complains that test(s << t) is ambiguous
// for Foo
static bool const value = sizeof( test(s << t) ) == sizeof( yes );
};
}
template<typename T>
struct has_ostream_operator :
has_ostream_operator_impl::has_ostream_operator<T> {
};
// template<class, class = std::void_t<>>
// struct has_ostream_operator : std::false_type {};
// template<class T>
// struct has_ostream_operator<
// T,
// std::void_t<
// decltype(std::declval<std::ostream&>() << std::declval<const T&>())>>
// : std::true_type {};
}
template<class X>
void prettyPrint(std::ostream& o, const X& x)
{
o << typeid(x).name() << ": " << detail::has_ostream_operator<X>::value;
}
struct Foo {
friend std::ostream& operator>>(std::ostream& o, Foo& f) {
return o;
}
friend std::ostream& operator<<(std::ostream& o, Foo& f) {
return o;
}
};
struct Bar {};
int main()
{
Bar x;
Foo y;
prettyPrint(std::cout, x); // 3Bar: 0
std::cout << std::endl;
prettyPrint(std::cout, y); // 3Foo: 1
std::cout << std::endl;
return 0;
}
@ArnCarveris
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment