#include <iostream>
#include <type_traits>
#include <string>
using namespace std;
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
template <typename H>
auto foo (H h, enable_if_t<
is_same<typename result_of<H(A)>::type, bool>::value>* = 0)
{
return [h] (B x) { return h (A {}); };
}
template <typename H>
auto foo (H h, enable_if_t<
is_same<typename result_of<H(B)>::type, bool>::value>* = 0)
{
return [h] (C x) { return h (B {}); };
}
template <typename H>
auto foo (H h, enable_if_t<
is_same<typename result_of<H(C)>::type, bool>::value>* = 0)
{
return [h] (D x) { return h (C {}); };
}
template <typename H>
auto foo (H h, enable_if_t<
is_same<typename result_of<H(D)>::type, bool>::value>* = 0)
{
return [h] (E x) { return h (D {}); };
}
struct fooify {
template<class...Args>
auto operator()(Args&&...args)const{
return foo(std::forward<Args>(args)...);
}
};
template<class Action, template<class...>class test, class Arg, class=void>
struct repeat_until_helper {
using action_result = result_of_t< Action&(Arg) >;
auto operator()(Action&& action, Arg&&arg)const {
return repeat_until_helper<Action, test, action_result>{}(
std::forward<Action>(action),
action( std::forward<Arg>(arg) )
);
}
};
template<class Action, template<class...>class test, class Arg>
struct repeat_until_helper< Action, test, Arg,
std::enable_if_t< test<Arg>{} >
> {
auto operator()(Action&& action, Arg&&arg)const {
return std::forward<Arg>(arg);
}
};
template<class X, class=void>
struct can_be_called_with_E:std::false_type{};
template<class X>
struct can_be_called_with_E<X,
decltype(
void(
std::declval<X>()(std::declval<E>())
)
)
>:std::true_type{};
template<template<class...>class test, class Action, class Arg>
auto repeat_until( Action&& action, Arg&& arg) {
return repeat_until_helper< Action, test, Arg >{}( std::forward<Action>(action), std::forward<Arg>(arg) );
}
int main ()
{
auto inner_handler = [] (A) -> bool { return false; };
auto f = repeat_until< can_be_called_with_E >( fooify{}, inner_handler );
// auto f = foo (foo (foo (foo ( inner_handler ))));
// auto f = call_until<E> ( inner_handler );
std::cout << f (E {}) << "\n";
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CiNpbmNsdWRlIDxzdHJpbmc+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgpzdHJ1Y3QgQSB7fTsKc3RydWN0IEIge307CnN0cnVjdCBDIHt9OwpzdHJ1Y3QgRCB7fTsKc3RydWN0IEUge307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgSD4KYXV0byBmb28gKEggaCwgZW5hYmxlX2lmX3Q8CiAgaXNfc2FtZTx0eXBlbmFtZSByZXN1bHRfb2Y8SChBKT46OnR5cGUsIGJvb2w+Ojp2YWx1ZT4qID0gMCkKewoJcmV0dXJuIFtoXSAoQiB4KSB7IHJldHVybiBoIChBIHt9KTsgfTsKfQoKdGVtcGxhdGUgPHR5cGVuYW1lIEg+CmF1dG8gZm9vIChIIGgsIGVuYWJsZV9pZl90PAogIGlzX3NhbWU8dHlwZW5hbWUgcmVzdWx0X29mPEgoQik+Ojp0eXBlLCBib29sPjo6dmFsdWU+KiA9IDApCnsKCXJldHVybiBbaF0gKEMgeCkgeyByZXR1cm4gaCAoQiB7fSk7IH07Cn0KCnRlbXBsYXRlIDx0eXBlbmFtZSBIPgphdXRvIGZvbyAoSCBoLCBlbmFibGVfaWZfdDwKICBpc19zYW1lPHR5cGVuYW1lIHJlc3VsdF9vZjxIKEMpPjo6dHlwZSwgYm9vbD46OnZhbHVlPiogPSAwKQp7CglyZXR1cm4gW2hdIChEIHgpIHsgcmV0dXJuIGggKEMge30pOyB9Owp9Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgSD4KYXV0byBmb28gKEggaCwgZW5hYmxlX2lmX3Q8CiAgaXNfc2FtZTx0eXBlbmFtZSByZXN1bHRfb2Y8SChEKT46OnR5cGUsIGJvb2w+Ojp2YWx1ZT4qID0gMCkKewoJcmV0dXJuIFtoXSAoRSB4KSB7IHJldHVybiBoIChEIHt9KTsgfTsKfQoKICAgIHN0cnVjdCBmb29pZnkgewogICAgICB0ZW1wbGF0ZTxjbGFzcy4uLkFyZ3M+CiAgICAgIGF1dG8gb3BlcmF0b3IoKShBcmdzJiYuLi5hcmdzKWNvbnN0ewogICAgICAgIHJldHVybiBmb28oc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKTsKICAgICAgfQogICAgfTsKCiAgICB0ZW1wbGF0ZTxjbGFzcyBBY3Rpb24sIHRlbXBsYXRlPGNsYXNzLi4uPmNsYXNzIHRlc3QsIGNsYXNzIEFyZywgY2xhc3M9dm9pZD4KICAgIHN0cnVjdCByZXBlYXRfdW50aWxfaGVscGVyIHsKICAgICAgdXNpbmcgYWN0aW9uX3Jlc3VsdCA9IHJlc3VsdF9vZl90PCBBY3Rpb24mKEFyZykgPjsKICAgICAgYXV0byBvcGVyYXRvcigpKEFjdGlvbiYmIGFjdGlvbiwgQXJnJiZhcmcpY29uc3QgewogICAgICAgIHJldHVybiByZXBlYXRfdW50aWxfaGVscGVyPEFjdGlvbiwgdGVzdCwgYWN0aW9uX3Jlc3VsdD57fSgKICAgICAgICAgIHN0ZDo6Zm9yd2FyZDxBY3Rpb24+KGFjdGlvbiksCiAgICAgICAgICBhY3Rpb24oIHN0ZDo6Zm9yd2FyZDxBcmc+KGFyZykgKQogICAgICAgICk7CiAgICAgIH0KICAgIH07CiAgICB0ZW1wbGF0ZTxjbGFzcyBBY3Rpb24sIHRlbXBsYXRlPGNsYXNzLi4uPmNsYXNzIHRlc3QsIGNsYXNzIEFyZz4KICAgIHN0cnVjdCByZXBlYXRfdW50aWxfaGVscGVyPCBBY3Rpb24sIHRlc3QsIEFyZywKICAgICAgc3RkOjplbmFibGVfaWZfdDwgdGVzdDxBcmc+e30gPgogICAgPiB7CiAgICAgIGF1dG8gb3BlcmF0b3IoKShBY3Rpb24mJiBhY3Rpb24sIEFyZyYmYXJnKWNvbnN0IHsKICAgICAgICByZXR1cm4gc3RkOjpmb3J3YXJkPEFyZz4oYXJnKTsKICAgICAgfQogICAgfTsKCgl0ZW1wbGF0ZTxjbGFzcyBYLCBjbGFzcz12b2lkPgoJc3RydWN0IGNhbl9iZV9jYWxsZWRfd2l0aF9FOnN0ZDo6ZmFsc2VfdHlwZXt9OwoJdGVtcGxhdGU8Y2xhc3MgWD4KCXN0cnVjdCBjYW5fYmVfY2FsbGVkX3dpdGhfRTxYLAoJCWRlY2x0eXBlKAoJCQl2b2lkKAoJCQkJc3RkOjpkZWNsdmFsPFg+KCkoc3RkOjpkZWNsdmFsPEU+KCkpCgkJCSkKCQkpCgk+OnN0ZDo6dHJ1ZV90eXBle307CgkKCXRlbXBsYXRlPHRlbXBsYXRlPGNsYXNzLi4uPmNsYXNzIHRlc3QsIGNsYXNzIEFjdGlvbiwgY2xhc3MgQXJnPgoJYXV0byByZXBlYXRfdW50aWwoIEFjdGlvbiYmIGFjdGlvbiwgQXJnJiYgYXJnKSB7CgkJcmV0dXJuIHJlcGVhdF91bnRpbF9oZWxwZXI8IEFjdGlvbiwgdGVzdCwgQXJnID57fSggc3RkOjpmb3J3YXJkPEFjdGlvbj4oYWN0aW9uKSwgc3RkOjpmb3J3YXJkPEFyZz4oYXJnKSApOwoJfQppbnQgbWFpbiAoKQp7CglhdXRvIGlubmVyX2hhbmRsZXIgPSBbXSAoQSkgLT4gYm9vbCB7IHJldHVybiBmYWxzZTsgfTsKCglhdXRvIGYgPSByZXBlYXRfdW50aWw8IGNhbl9iZV9jYWxsZWRfd2l0aF9FID4oIGZvb2lmeXt9LCBpbm5lcl9oYW5kbGVyICk7CgkvLyBhdXRvIGYgPSBmb28gKGZvbyAoZm9vIChmb28gKCBpbm5lcl9oYW5kbGVyICkpKSk7Ci8vCWF1dG8gZiA9IGNhbGxfdW50aWw8RT4gKCBpbm5lcl9oYW5kbGVyICk7CgoJc3RkOjpjb3V0IDw8IGYgKEUge30pIDw8ICJcbiI7Cn0=