Last active
January 11, 2024 14:52
-
-
Save ArnCarveris/e68fdf559fce1d634ebbec00fd5e8414 to your computer and use it in GitHub Desktop.
has_ostream_operator for C++98
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
try online