#include <iostream>
template<typename T, typename LogFunc>
class Foo {
public:
Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
template<typename LFN>
Foo& operator+=(const Foo<T, LFN>& other) {
lfn_(t_, other());
t_ += other();
return *this;
}
T operator()() const { return t_; }
private:
T t_;
LogFunc lfn_;
};
template<typename T, typename LogFunc>
std::ostream& operator<<(std::ostream& o, const Foo<T, LogFunc>& f) {
return o << f();
}
// It's actually amazing that this works, and I presume that it works because it
// is only used in an inline function, from which it can be resolved at
// compile-time.
struct Noop {
template<typename...A>
void operator()(A...) { };
};
template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
return Foo<T, LogFunc>(t, func);
}
template<typename T>
void log(std::ostream& o, const T& a, const T& b) {
o << "a: " << a << " b: " << b << std::endl;
}
int main(int argc, char**argv) {
auto f1 = make_foo(3.141592653);
auto f2 = make_foo(2.5, [&](double a, double b) { log(std::cout, a, b); });
f1 += f2;
f2 += f1;
std::cout << "f1: " << f1 << " f2: " << f2 << std::endl;
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgoKCnRlbXBsYXRlPHR5cGVuYW1lIFQsIHR5cGVuYW1lIExvZ0Z1bmM+CmNsYXNzIEZvbyB7CiAgcHVibGljOgogICAgRm9vKGNvbnN0IFQmIHQsIExvZ0Z1bmMgZm4pIDogdF8odCksIGxmbl8oZm4pIHt9CgogICAgdGVtcGxhdGU8dHlwZW5hbWUgTEZOPgogICAgRm9vJiBvcGVyYXRvcis9KGNvbnN0IEZvbzxULCBMRk4+JiBvdGhlcikgewogICAgICBsZm5fKHRfLCBvdGhlcigpKTsKICAgICAgdF8gKz0gb3RoZXIoKTsKICAgICAgcmV0dXJuICp0aGlzOwogICAgfQogICAgVCBvcGVyYXRvcigpKCkgY29uc3QgeyByZXR1cm4gdF87IH0KCiAgcHJpdmF0ZToKICAgIFQgdF87CiAgICBMb2dGdW5jIGxmbl87Cn07Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZSBMb2dGdW5jPgpzdGQ6Om9zdHJlYW0mIG9wZXJhdG9yPDwoc3RkOjpvc3RyZWFtJiBvLCBjb25zdCBGb288VCwgTG9nRnVuYz4mIGYpIHsKICByZXR1cm4gbyA8PCBmKCk7Cn0KCi8vIEl0J3MgYWN0dWFsbHkgYW1hemluZyB0aGF0IHRoaXMgd29ya3MsIGFuZCBJIHByZXN1bWUgdGhhdCBpdCB3b3JrcyBiZWNhdXNlIGl0Ci8vIGlzIG9ubHkgdXNlZCBpbiBhbiBpbmxpbmUgZnVuY3Rpb24sIGZyb20gd2hpY2ggaXQgY2FuIGJlIHJlc29sdmVkIGF0Ci8vIGNvbXBpbGUtdGltZS4Kc3RydWN0IE5vb3AgewogIHRlbXBsYXRlPHR5cGVuYW1lLi4uQT4KICB2b2lkIG9wZXJhdG9yKCkoQS4uLikgeyB9Owp9OwoKdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUgTG9nRnVuYz1Ob29wPgpGb288VCwgTG9nRnVuYz4gbWFrZV9mb28oY29uc3QgVCYgdCwgTG9nRnVuYyBmdW5jPUxvZ0Z1bmMoKSkgewogIHJldHVybiBGb288VCwgTG9nRnVuYz4odCwgZnVuYyk7Cn0KCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnZvaWQgbG9nKHN0ZDo6b3N0cmVhbSYgbywgY29uc3QgVCYgYSwgY29uc3QgVCYgYikgewogIG8gPDwgImE6ICIgPDwgYSA8PCAiIGI6ICIgPDwgYiA8PCBzdGQ6OmVuZGw7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyKiphcmd2KSB7CiAgYXV0byBmMSA9IG1ha2VfZm9vKDMuMTQxNTkyNjUzKTsKICBhdXRvIGYyID0gbWFrZV9mb28oMi41LCBbJl0oZG91YmxlIGEsIGRvdWJsZSBiKSB7IGxvZyhzdGQ6OmNvdXQsIGEsIGIpOyB9KTsKICBmMSArPSBmMjsKICBmMiArPSBmMTsKICBzdGQ6OmNvdXQgPDwgImYxOiAiIDw8IGYxIDw8ICIgZjI6ICIgPDwgZjIgPDwgc3RkOjplbmRsOwogIHJldHVybiAwOwp9