#include <iostream>
#include <type_traits>
#include <memory>
using namespace std;
template<typename T> struct foo {
virtual foo& operator<<(const T& e) const { std::cout << "check foo\n"; }
};
struct derived : foo<int> {
virtual derived& operator<<(const int& e) const { std::cout << "check derived\n"; }
};
template<typename T> struct genericDerived : foo<T> {
virtual derived& operator<<(const T& e) const { std::cout << "check genericDerived\n"; }
};
//////
namespace detail
{
template<typename Foo, typename T>
const std::shared_ptr<Foo>& dispatch_lshift(const std::shared_ptr<Foo>& o, const T& e, const std::true_type& enabler)
{
*o << e;
return o;
}
}
template<typename Foo, typename T>
const std::shared_ptr<Foo>& operator<<(const std::shared_ptr<Foo>& o, const T& e)
{
return detail::dispatch_lshift(o, e, std::is_convertible<Foo*, foo<T>* >());
}
int main()
{
auto f = make_shared<foo<int>>();
f << 1;
auto d = make_shared<derived>();
d << 2;
auto g = make_shared<genericDerived<int>>();
g << 3;
auto x = make_shared<int>();
// x << 4; // correctly FAILS to compile
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CiNpbmNsdWRlIDxtZW1vcnk+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBUPiBzdHJ1Y3QgZm9vIHsKICAgIHZpcnR1YWwgZm9vJiBvcGVyYXRvcjw8KGNvbnN0IFQmIGUpIGNvbnN0IHsgc3RkOjpjb3V0IDw8ICJjaGVjayBmb29cbiI7IH0KfTsKCnN0cnVjdCBkZXJpdmVkIDogZm9vPGludD4gewogICAgdmlydHVhbCBkZXJpdmVkJiBvcGVyYXRvcjw8KGNvbnN0IGludCYgZSkgY29uc3QgeyBzdGQ6OmNvdXQgPDwgImNoZWNrIGRlcml2ZWRcbiI7IH0KfTsKCnRlbXBsYXRlPHR5cGVuYW1lIFQ+IHN0cnVjdCBnZW5lcmljRGVyaXZlZCA6IGZvbzxUPiB7CiAgICB2aXJ0dWFsIGRlcml2ZWQmIG9wZXJhdG9yPDwoY29uc3QgVCYgZSkgY29uc3QgeyBzdGQ6OmNvdXQgPDwgImNoZWNrIGdlbmVyaWNEZXJpdmVkXG4iOyB9Cn07CgovLy8vLy8KCm5hbWVzcGFjZSBkZXRhaWwKewoJdGVtcGxhdGU8dHlwZW5hbWUgRm9vLCB0eXBlbmFtZSBUPgoJCWNvbnN0IHN0ZDo6c2hhcmVkX3B0cjxGb28+JiBkaXNwYXRjaF9sc2hpZnQoY29uc3Qgc3RkOjpzaGFyZWRfcHRyPEZvbz4mIG8sIGNvbnN0IFQmIGUsIGNvbnN0IHN0ZDo6dHJ1ZV90eXBlJiBlbmFibGVyKQoJCXsKCQkJKm8gPDwgZTsKCQkJcmV0dXJuIG87CgkJfQp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBGb28sIHR5cGVuYW1lIFQ+CmNvbnN0IHN0ZDo6c2hhcmVkX3B0cjxGb28+JiBvcGVyYXRvcjw8KGNvbnN0IHN0ZDo6c2hhcmVkX3B0cjxGb28+JiBvLCBjb25zdCBUJiBlKQp7CglyZXR1cm4gZGV0YWlsOjpkaXNwYXRjaF9sc2hpZnQobywgZSwgc3RkOjppc19jb252ZXJ0aWJsZTxGb28qLCBmb288VD4qID4oKSk7Cn0KCmludCBtYWluKCkKewoJYXV0byBmID0gbWFrZV9zaGFyZWQ8Zm9vPGludD4+KCk7CglmIDw8IDE7CgoJYXV0byBkID0gbWFrZV9zaGFyZWQ8ZGVyaXZlZD4oKTsKCWQgPDwgMjsKCglhdXRvIGcgPSBtYWtlX3NoYXJlZDxnZW5lcmljRGVyaXZlZDxpbnQ+PigpOwoJZyA8PCAzOwoKCWF1dG8geCA9IG1ha2Vfc2hhcmVkPGludD4oKTsKCS8vIHggPDwgNDsgLy8gY29ycmVjdGx5IEZBSUxTIHRvIGNvbXBpbGUKfQo=