#include <iostream>
#include <tuple>
//function traits
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename C, typename R, typename... A>
struct function_traits<R(C::*)(A...) const>
{
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
};
};
template<typename InArg, typename Function>
class selfCompose {
Function f;
public:
selfCompose(Function f): f(f) {}
auto operator() (InArg x) -> decltype(f(f(x)))
{
return f(f(x));
}
};
template<typename Fun>
selfCompose<typename function_traits<Fun>::template arg<0>::type, Fun>
make_selfCompose(Fun f)
{
typedef typename function_traits<Fun>::template arg<0>::type InArg;
return selfCompose<InArg, decltype(f)>(f);
}
int main() {
auto f = [](int x){return x*x;};
std::cout << make_selfCompose(f)(4)
<< std::endl;
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHVwbGU+CgovL2Z1bmN0aW9uIHRyYWl0cwp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4Kc3RydWN0IGZ1bmN0aW9uX3RyYWl0cyA6IHB1YmxpYyBmdW5jdGlvbl90cmFpdHM8ZGVjbHR5cGUoJlQ6Om9wZXJhdG9yKCkpPgp7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBDLCB0eXBlbmFtZSBSLCB0eXBlbmFtZS4uLiBBPgpzdHJ1Y3QgZnVuY3Rpb25fdHJhaXRzPFIoQzo6KikoQS4uLikgY29uc3Q+CnsKICAgdGVtcGxhdGUgPHNpemVfdCBpPgogICBzdHJ1Y3QgYXJnCiAgIHsKICAgICAgdHlwZWRlZiB0eXBlbmFtZSBzdGQ6OnR1cGxlX2VsZW1lbnQ8aSwgc3RkOjp0dXBsZTxBLi4uPj46OnR5cGUgdHlwZTsKICAgfTsKfTsKCnRlbXBsYXRlPHR5cGVuYW1lIEluQXJnLCB0eXBlbmFtZSBGdW5jdGlvbj4KY2xhc3Mgc2VsZkNvbXBvc2UgewogIEZ1bmN0aW9uIGY7CiBwdWJsaWM6CiAgc2VsZkNvbXBvc2UoRnVuY3Rpb24gZik6IGYoZikge30KICBhdXRvIG9wZXJhdG9yKCkgKEluQXJnIHgpIC0+IGRlY2x0eXBlKGYoZih4KSkpIAogIHsKICAgIHJldHVybiBmKGYoeCkpOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIH0KfTsKCnRlbXBsYXRlPHR5cGVuYW1lIEZ1bj4Kc2VsZkNvbXBvc2U8dHlwZW5hbWUgZnVuY3Rpb25fdHJhaXRzPEZ1bj46OnRlbXBsYXRlIGFyZzwwPjo6dHlwZSwgRnVuPgptYWtlX3NlbGZDb21wb3NlKEZ1biBmKQp7CiAgdHlwZWRlZiB0eXBlbmFtZSBmdW5jdGlvbl90cmFpdHM8RnVuPjo6dGVtcGxhdGUgYXJnPDA+Ojp0eXBlIEluQXJnOwogIHJldHVybiBzZWxmQ29tcG9zZTxJbkFyZywgZGVjbHR5cGUoZik+KGYpOwp9CgppbnQgbWFpbigpIHsKICBhdXRvIGYgPSBbXShpbnQgeCl7cmV0dXJuIHgqeDt9OwogIHN0ZDo6Y291dCA8PCBtYWtlX3NlbGZDb21wb3NlKGYpKDQpCiAgICAgICAgICAgIDw8IHN0ZDo6ZW5kbDsKICByZXR1cm4gMDsKfQoK