#include <iostream>
#include <memory>
template<typename T>
struct A {
T value_;
A(T value) : value_(value) {}
void sayHello() const {
std::cout << "Hello from A! " << value_ << '\n';
}
};
template<typename T>
struct B {
T value_;
B(T value) : value_(value) {}
void sayHello() const {
std::cout << "Hello from B! " << value_ << '\n';
}
};
class Wrapper {
private:
class Concept {
public:
virtual ~Concept() = default;
virtual void sayHello() const = 0;
};
template<typename T>
class Model final
: public Concept {
private:
T data_;
public:
Model(T data) : data_(data) {}
virtual void sayHello() const override {
data_.sayHello();
}
private:
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs) {
T x = static_cast<const Model<T> &>(lhs).data_;
x.sayHello();
rhs.sayHello();
auto y = x.value_ + rhs.value_;
std::cout << y << '\n';
}
};
template<typename U>
friend inline void doSomething(const Concept &lhs, const B<U> &rhs);
std::shared_ptr<const Concept> ptr_;
public:
template<typename T>
explicit inline Wrapper(T a)
: ptr_(std::make_shared<Model<A<T>>>(std::move(a))) {}
template<typename U>
friend inline void someFriend(Wrapper &lhs, B<U> &rhs) {
doSomething(*lhs.ptr_, rhs);
}
};
int main() {
Wrapper a(1);
B<int> b{2};
someFriend(a, b);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWVtb3J5PgoKdGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RydWN0IEEgewogIFQgdmFsdWVfOwoKICBBKFQgdmFsdWUpIDogdmFsdWVfKHZhbHVlKSB7fQoKICB2b2lkIHNheUhlbGxvKCkgY29uc3QgewogICAgc3RkOjpjb3V0IDw8ICJIZWxsbyBmcm9tIEEhICIgPDwgdmFsdWVfIDw8ICdcbic7CiAgfQp9Owp0ZW1wbGF0ZTx0eXBlbmFtZSBUPgpzdHJ1Y3QgQiB7CiAgVCB2YWx1ZV87CgogIEIoVCB2YWx1ZSkgOiB2YWx1ZV8odmFsdWUpIHt9CgogIHZvaWQgc2F5SGVsbG8oKSBjb25zdCB7CiAgICBzdGQ6OmNvdXQgPDwgIkhlbGxvIGZyb20gQiEgIiA8PCB2YWx1ZV8gPDwgJ1xuJzsKICB9Cn07CgpjbGFzcyBXcmFwcGVyIHsKcHJpdmF0ZToKICBjbGFzcyBDb25jZXB0IHsKICBwdWJsaWM6CiAgICB2aXJ0dWFsIH5Db25jZXB0KCkgPSBkZWZhdWx0OwoKICAgIHZpcnR1YWwgdm9pZCBzYXlIZWxsbygpIGNvbnN0ID0gMDsKICB9OwoKICB0ZW1wbGF0ZTx0eXBlbmFtZSBUPgogIGNsYXNzIE1vZGVsIGZpbmFsCiAgICAgIDogcHVibGljIENvbmNlcHQgewogIHByaXZhdGU6CiAgICBUIGRhdGFfOwoKICBwdWJsaWM6CiAgICBNb2RlbChUIGRhdGEpIDogZGF0YV8oZGF0YSkge30KCiAgICB2aXJ0dWFsIHZvaWQgc2F5SGVsbG8oKSBjb25zdCBvdmVycmlkZSB7CiAgICAgIGRhdGFfLnNheUhlbGxvKCk7CiAgICB9CgogIHByaXZhdGU6CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBVPgogICAgZnJpZW5kIGlubGluZSB2b2lkIGRvU29tZXRoaW5nKGNvbnN0IENvbmNlcHQgJmxocywgY29uc3QgQjxVPiAmcmhzKSB7CiAgICAgIFQgeCA9IHN0YXRpY19jYXN0PGNvbnN0IE1vZGVsPFQ+ICY+KGxocykuZGF0YV87CgogICAgICB4LnNheUhlbGxvKCk7CiAgICAgIHJocy5zYXlIZWxsbygpOwoKICAgICAgYXV0byB5ID0geC52YWx1ZV8gKyByaHMudmFsdWVfOwoKICAgICAgc3RkOjpjb3V0IDw8IHkgPDwgJ1xuJzsKICAgIH0KICB9OwoKICB0ZW1wbGF0ZTx0eXBlbmFtZSBVPgogIGZyaWVuZCBpbmxpbmUgdm9pZCBkb1NvbWV0aGluZyhjb25zdCBDb25jZXB0ICZsaHMsIGNvbnN0IEI8VT4gJnJocyk7CgogIHN0ZDo6c2hhcmVkX3B0cjxjb25zdCBDb25jZXB0PiBwdHJfOwoKcHVibGljOgogIHRlbXBsYXRlPHR5cGVuYW1lIFQ+CiAgZXhwbGljaXQgaW5saW5lIFdyYXBwZXIoVCBhKQogICAgICA6IHB0cl8oc3RkOjptYWtlX3NoYXJlZDxNb2RlbDxBPFQ+Pj4oc3RkOjptb3ZlKGEpKSkge30KCiAgdGVtcGxhdGU8dHlwZW5hbWUgVT4KICBmcmllbmQgaW5saW5lIHZvaWQgc29tZUZyaWVuZChXcmFwcGVyICZsaHMsIEI8VT4gJnJocykgewogICAgZG9Tb21ldGhpbmcoKmxocy5wdHJfLCByaHMpOwogIH0KfTsKCmludCBtYWluKCkgewogIFdyYXBwZXIgYSgxKTsKICBCPGludD4gYnsyfTsKCiAgc29tZUZyaWVuZChhLCBiKTsKICAKICByZXR1cm4gMDsKfQ==