#include <iostream>
#include <string>
#include <type_traits>
namespace has_insertion_operator_impl {
typedef char no;
typedef char yes[2];
struct any_t {
template<typename T> any_t( T const& );
};
no operator<<( std::ostream const&, any_t const& );
yes& test( std::ostream& );
no test( no );
template<typename T>
struct has_insertion_operator {
static std::ostream &s;
static T const &t;
static bool const value = sizeof( test(s << t) ) == sizeof( yes );
};
}
template<typename T>
struct has_insertion_operator :
has_insertion_operator_impl::has_insertion_operator<T> {
};
template <typename T,
typename std::enable_if<has_insertion_operator<T>::value, T>::type* = nullptr>
void print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T,
typename std::enable_if<!has_insertion_operator<T>::value, T>::type* = nullptr>
void print(T obj) {
std::cout << obj.to_string() << std::endl;
}
struct Foo
{
public:
friend std::ostream& operator<<(std::ostream & os, Foo const& foo);
};
struct Bar
{
public:
std::string to_string() const
{
return "from to_string()";
}
};
int main()
{
print<Foo>(Foo());
print<Bar>(Bar());
//print<Bar>(Foo()); doesn't compile
//print<Foo>(Bar()); doesn't compile
print(Foo());
print(Bar());
print(42);
print('a');
print(std::string("Hi"));
print("Hey");
//print({1, 2, 3}); doesn't compile
return 0;
}
ICAgICNpbmNsdWRlIDxpb3N0cmVhbT4KICAgICNpbmNsdWRlIDxzdHJpbmc+CiAgICAjaW5jbHVkZSA8dHlwZV90cmFpdHM+CgogICAgbmFtZXNwYWNlIGhhc19pbnNlcnRpb25fb3BlcmF0b3JfaW1wbCB7CiAgICAgIHR5cGVkZWYgY2hhciBubzsKICAgICAgdHlwZWRlZiBjaGFyIHllc1syXTsKCiAgICAgIHN0cnVjdCBhbnlfdCB7CiAgICAgICAgdGVtcGxhdGU8dHlwZW5hbWUgVD4gYW55X3QoIFQgY29uc3QmICk7CiAgICAgIH07CgogICAgICBubyBvcGVyYXRvcjw8KCBzdGQ6Om9zdHJlYW0gY29uc3QmLCBhbnlfdCBjb25zdCYgKTsKCiAgICAgIHllcyYgdGVzdCggc3RkOjpvc3RyZWFtJiApOwogICAgICBubyB0ZXN0KCBubyApOwoKICAgICAgdGVtcGxhdGU8dHlwZW5hbWUgVD4KICAgICAgc3RydWN0IGhhc19pbnNlcnRpb25fb3BlcmF0b3IgewogICAgICAgIHN0YXRpYyBzdGQ6Om9zdHJlYW0gJnM7CiAgICAgICAgc3RhdGljIFQgY29uc3QgJnQ7CiAgICAgICAgc3RhdGljIGJvb2wgY29uc3QgdmFsdWUgPSBzaXplb2YoIHRlc3QocyA8PCB0KSApID09IHNpemVvZiggeWVzICk7CiAgICAgIH07CiAgICB9CgogICAgdGVtcGxhdGU8dHlwZW5hbWUgVD4KICAgIHN0cnVjdCBoYXNfaW5zZXJ0aW9uX29wZXJhdG9yIDoKICAgICAgaGFzX2luc2VydGlvbl9vcGVyYXRvcl9pbXBsOjpoYXNfaW5zZXJ0aW9uX29wZXJhdG9yPFQ+IHsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFQsCiAgICAgICAgdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8aGFzX2luc2VydGlvbl9vcGVyYXRvcjxUPjo6dmFsdWUsIFQ+Ojp0eXBlKiA9IG51bGxwdHI+CiAgICB2b2lkIHByaW50KFQgb2JqKSB7CiAgICAgICAgc3RkOjpjb3V0IDw8ICJmcm9tIHByaW50KCkiIDw8IHN0ZDo6ZW5kbDsKICAgIH0KCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwKICAgICAgICB0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjwhaGFzX2luc2VydGlvbl9vcGVyYXRvcjxUPjo6dmFsdWUsIFQ+Ojp0eXBlKiA9IG51bGxwdHI+CiAgICB2b2lkIHByaW50KFQgb2JqKSB7CiAgICAgICAgc3RkOjpjb3V0IDw8IG9iai50b19zdHJpbmcoKSA8PCBzdGQ6OmVuZGw7CiAgICB9CgogICAgc3RydWN0IEZvbwogICAgewogICAgcHVibGljOgogICAgICAgIGZyaWVuZCBzdGQ6Om9zdHJlYW0mIG9wZXJhdG9yPDwoc3RkOjpvc3RyZWFtICYgb3MsIEZvbyBjb25zdCYgZm9vKTsKICAgIH07CgogICAgc3RydWN0IEJhcgogICAgewogICAgcHVibGljOgogICAgICAgIHN0ZDo6c3RyaW5nIHRvX3N0cmluZygpIGNvbnN0CiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gImZyb20gdG9fc3RyaW5nKCkiOwogICAgICAgIH0KICAgIH07CgogICAgaW50IG1haW4oKQogICAgewogICAgICAgIHByaW50PEZvbz4oRm9vKCkpOwogICAgICAgIHByaW50PEJhcj4oQmFyKCkpOwoKICAgICAgICAvL3ByaW50PEJhcj4oRm9vKCkpOyBkb2Vzbid0IGNvbXBpbGUKICAgICAgICAvL3ByaW50PEZvbz4oQmFyKCkpOyBkb2Vzbid0IGNvbXBpbGUKCiAgICAgICAgcHJpbnQoRm9vKCkpOwogICAgICAgIHByaW50KEJhcigpKTsKCiAgICAgICAgcHJpbnQoNDIpOwogICAgICAgIHByaW50KCdhJyk7CiAgICAgICAgcHJpbnQoc3RkOjpzdHJpbmcoIkhpIikpOwogICAgICAgIHByaW50KCJIZXkiKTsKICAgICAgICAvL3ByaW50KHsxLCAyLCAzfSk7IGRvZXNuJ3QgY29tcGlsZQogICAgICAgIHJldHVybiAwOwogICAgfQo=