#include <type_traits>
#include <utility>
#include <typeinfo>
#include <cassert>
#include <stdexcept>
template<std::size_t index, class...Ts> struct get_variadic_by_index;
template<std::size_t index, class First, class...Rests> struct get_variadic_by_index<index,First,Rests...> : public get_variadic_by_index<index-1,Rests...> {};
template<class First, class...Rests> struct get_variadic_by_index<0,First,Rests...> {typedef First type;};
template<class func_type, class LBase, class RBase, class LTypes, class RTypes> class double_dispatch;
template<class func_type, class LBase, class RBase, class...Ls, class...Rs>
class double_dispatch<func_type, LBase, RBase, std::tuple<Ls...>,std::tuple<Rs...>>
{
typedef decltype(std::declval<func_type>()(
std::declval<typename get_variadic_by_index<0,Ls...>::type*>(),
std::declval<typename get_variadic_by_index<0,Rs...>::type*>()
)) return_type;
template<int LI, int RI>
return_type call(LBase* l, RBase* r)
{
return func(
static_cast<typename get_variadic_by_index<LI,Ls...>::type*>(l),
static_cast<typename get_variadic_by_index<RI,Rs...>::type*>(r)
);
}
template<int LI>
return_type iter_right_types(LBase*, RBase*, const std::type_info&, std::integral_constant<int,sizeof...(Rs)>)
{assert("typeid(r) is not in tuple list"); throw std::bad_cast();}
template<int LI, int RI>
return_type iter_right_types(LBase* l, RBase* r, const std::type_info& righttype, std::integral_constant<int,RI>)
{
if (righttype==typeid(typename get_variadic_by_index<RI,Rs...>::type))
return call<LI,RI>(l, r);
else
return iter_right_types<LI>(l, r, righttype, std::integral_constant<int,RI+1>());
}
return_type iter_left_types(LBase*, RBase*, const std::type_info&, std::integral_constant<int,sizeof...(Ls)>)
{assert("typeid(l) is not in tuple list"); throw std::bad_cast();}
template<int LI>
return_type iter_left_types(LBase* l, RBase* r, const std::type_info& lefttype, std::integral_constant<int,LI>)
{
if (lefttype==typeid(typename get_variadic_by_index<LI,Ls...>::type))
return iter_right_types<LI>(l, r, typeid(*r), std::integral_constant<int,0>());
else
return iter_left_types(l, r, lefttype, std::integral_constant<int,LI+1>());
}
func_type func;
public:
explicit double_dispatch(func_type func) : func(func) {}
return_type operator()(LBase* l, RBase* r)
{return iter_left_types(l, r, typeid(*l), std::integral_constant<int,0>());}
return_type dispatch(LBase* l, RBase* r)
{return iter_left_types(l, r, typeid(*l), std::integral_constant<int,0>());}
};
#define DOUBLE_DISPATCHER(FUNC) \
struct {\
template<class L,class R> \
auto operator()(L&& l, R&& r) \
->decltype(FUNC(std::forward<L>(l),std::forward<R>(r))) \
{return FUNC(std::forward<L>(l),std::forward<R>(r));} \
}
#include <iostream>
struct Loud {
Loud() {std::cerr << "LOUD: default ctor\n";}
Loud(const Loud&) {std::cerr << "LOUD: copy ctor\n";}
Loud(Loud&&) {std::cerr << "LOUD: move ctor\n";}
~Loud() {std::cerr << "LOUD: dtor\n";}
Loud& operator=(const Loud&) {std::cerr << "LOUD: copy assign\n"; return *this;}
Loud& operator=(Loud&&) {std::cerr << "LOUD: move assign\n"; return *this;}
};
struct Letter {
virtual ~Letter() {}
};
struct A : public Letter {};
struct B : public Letter {};
struct C : public Letter {};
struct Number {
virtual ~Number() {}
};
struct One : public Number {};
struct Two : public Number {};
struct Three : public Number {};
Loud print(const A*,const One*) {std::cerr << "A1\n"; return {};}
Loud print(const A*,const Two*) {std::cerr << "A2\n"; return {};}
Loud print(const A*,const Three*) {std::cerr << "A3\n"; return {};}
Loud print(const B*,const One*) {std::cerr << "B1\n"; return {};}
Loud print(const B*,const Two*) {std::cerr << "B2\n"; return {};}
Loud print(const B*,const Three*) {std::cerr << "B3\n"; return {};}
Loud print(const C*,const One*) {std::cerr << "C1\n"; return {};}
Loud print(const C*,const Two*) {std::cerr << "C2\n"; return {};}
Loud print(const C*,const Three*) {std::cerr << "C3\n"; return {};}
DOUBLE_DISPATCHER(print) printdispatch;
double_dispatch<decltype(printdispatch), const Letter, const Number,
std::tuple<const A,const B,const C>,
std::tuple<const One,const Two,const Three>>
d_dispatcher(printdispatch);
int main()
{
const Letter& a = A{};
const Letter& b = B{};
const Letter& c = C{};
const Number& on = One{};
const Number& tw = Two{};
const Number& th = Three{};
d_dispatcher(&a,&on);
d_dispatcher(&a,&tw);
d_dispatcher(&a,&th);
d_dispatcher(&b,&on);
d_dispatcher(&b,&tw);
d_dispatcher(&b,&th);
d_dispatcher(&c,&on);
d_dispatcher(&c,&tw);
d_dispatcher(&c,&th);
return 0;
}
I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgojaW5jbHVkZSA8dXRpbGl0eT4KI2luY2x1ZGUgPHR5cGVpbmZvPgojaW5jbHVkZSA8Y2Fzc2VydD4KI2luY2x1ZGUgPHN0ZGV4Y2VwdD4KCnRlbXBsYXRlPHN0ZDo6c2l6ZV90IGluZGV4LCBjbGFzcy4uLlRzPiBzdHJ1Y3QgZ2V0X3ZhcmlhZGljX2J5X2luZGV4Owp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBpbmRleCwgY2xhc3MgRmlyc3QsIGNsYXNzLi4uUmVzdHM+IHN0cnVjdCBnZXRfdmFyaWFkaWNfYnlfaW5kZXg8aW5kZXgsRmlyc3QsUmVzdHMuLi4+IDogcHVibGljIGdldF92YXJpYWRpY19ieV9pbmRleDxpbmRleC0xLFJlc3RzLi4uPiB7fTsKdGVtcGxhdGU8Y2xhc3MgRmlyc3QsIGNsYXNzLi4uUmVzdHM+IHN0cnVjdCBnZXRfdmFyaWFkaWNfYnlfaW5kZXg8MCxGaXJzdCxSZXN0cy4uLj4ge3R5cGVkZWYgRmlyc3QgdHlwZTt9OwoKCnRlbXBsYXRlPGNsYXNzIGZ1bmNfdHlwZSwgY2xhc3MgTEJhc2UsIGNsYXNzIFJCYXNlLCBjbGFzcyBMVHlwZXMsIGNsYXNzIFJUeXBlcz4gY2xhc3MgZG91YmxlX2Rpc3BhdGNoOwp0ZW1wbGF0ZTxjbGFzcyBmdW5jX3R5cGUsIGNsYXNzIExCYXNlLCBjbGFzcyBSQmFzZSwgY2xhc3MuLi5McywgY2xhc3MuLi5Scz4gCmNsYXNzIGRvdWJsZV9kaXNwYXRjaDxmdW5jX3R5cGUsIExCYXNlLCBSQmFzZSwgc3RkOjp0dXBsZTxMcy4uLj4sc3RkOjp0dXBsZTxScy4uLj4+CnsKICAgIHR5cGVkZWYgZGVjbHR5cGUoc3RkOjpkZWNsdmFsPGZ1bmNfdHlwZT4oKSgKICAgICAgICBzdGQ6OmRlY2x2YWw8dHlwZW5hbWUgZ2V0X3ZhcmlhZGljX2J5X2luZGV4PDAsTHMuLi4+Ojp0eXBlKj4oKSwKICAgICAgICBzdGQ6OmRlY2x2YWw8dHlwZW5hbWUgZ2V0X3ZhcmlhZGljX2J5X2luZGV4PDAsUnMuLi4+Ojp0eXBlKj4oKQogICAgICAgICkpIHJldHVybl90eXBlOwoKICAgIHRlbXBsYXRlPGludCBMSSwgaW50IFJJPgogICAgcmV0dXJuX3R5cGUgY2FsbChMQmFzZSogbCwgUkJhc2UqIHIpCiAgICB7CiAgICAgICAgcmV0dXJuIGZ1bmMoCiAgICAgICAgICAgIHN0YXRpY19jYXN0PHR5cGVuYW1lIGdldF92YXJpYWRpY19ieV9pbmRleDxMSSxMcy4uLj46OnR5cGUqPihsKSwKICAgICAgICAgICAgc3RhdGljX2Nhc3Q8dHlwZW5hbWUgZ2V0X3ZhcmlhZGljX2J5X2luZGV4PFJJLFJzLi4uPjo6dHlwZSo+KHIpCiAgICAgICAgICAgICk7CiAgICB9CiAgICAKICAgIHRlbXBsYXRlPGludCBMST4KICAgIHJldHVybl90eXBlIGl0ZXJfcmlnaHRfdHlwZXMoTEJhc2UqLCBSQmFzZSosIGNvbnN0IHN0ZDo6dHlwZV9pbmZvJiwgc3RkOjppbnRlZ3JhbF9jb25zdGFudDxpbnQsc2l6ZW9mLi4uKFJzKT4pCiAgICB7YXNzZXJ0KCJ0eXBlaWQocikgaXMgbm90IGluIHR1cGxlIGxpc3QiKTsgdGhyb3cgc3RkOjpiYWRfY2FzdCgpO30KCiAgICB0ZW1wbGF0ZTxpbnQgTEksIGludCBSST4KICAgIHJldHVybl90eXBlIGl0ZXJfcmlnaHRfdHlwZXMoTEJhc2UqIGwsIFJCYXNlKiByLCBjb25zdCBzdGQ6OnR5cGVfaW5mbyYgcmlnaHR0eXBlLCBzdGQ6OmludGVncmFsX2NvbnN0YW50PGludCxSST4pCiAgICB7CiAgICAgICAgaWYgKHJpZ2h0dHlwZT09dHlwZWlkKHR5cGVuYW1lIGdldF92YXJpYWRpY19ieV9pbmRleDxSSSxScy4uLj46OnR5cGUpKQogICAgICAgICAgICByZXR1cm4gY2FsbDxMSSxSST4obCwgcik7CiAgICAgICAgZWxzZQogICAgICAgICAgICByZXR1cm4gaXRlcl9yaWdodF90eXBlczxMST4obCwgciwgcmlnaHR0eXBlLCBzdGQ6OmludGVncmFsX2NvbnN0YW50PGludCxSSSsxPigpKTsKICAgIH0KICAgIAogICAgcmV0dXJuX3R5cGUgaXRlcl9sZWZ0X3R5cGVzKExCYXNlKiwgUkJhc2UqLCBjb25zdCBzdGQ6OnR5cGVfaW5mbyYsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8aW50LHNpemVvZi4uLihMcyk+KQogICAge2Fzc2VydCgidHlwZWlkKGwpIGlzIG5vdCBpbiB0dXBsZSBsaXN0Iik7IHRocm93IHN0ZDo6YmFkX2Nhc3QoKTt9CgogICAgdGVtcGxhdGU8aW50IExJPgogICAgcmV0dXJuX3R5cGUgaXRlcl9sZWZ0X3R5cGVzKExCYXNlKiBsLCBSQmFzZSogciwgY29uc3Qgc3RkOjp0eXBlX2luZm8mIGxlZnR0eXBlLCBzdGQ6OmludGVncmFsX2NvbnN0YW50PGludCxMST4pCiAgICB7CiAgICAgICAgaWYgKGxlZnR0eXBlPT10eXBlaWQodHlwZW5hbWUgZ2V0X3ZhcmlhZGljX2J5X2luZGV4PExJLExzLi4uPjo6dHlwZSkpCiAgICAgICAgICAgIHJldHVybiBpdGVyX3JpZ2h0X3R5cGVzPExJPihsLCByLCB0eXBlaWQoKnIpLCBzdGQ6OmludGVncmFsX2NvbnN0YW50PGludCwwPigpKTsKICAgICAgICBlbHNlCiAgICAgICAgICAgIHJldHVybiBpdGVyX2xlZnRfdHlwZXMobCwgciwgbGVmdHR5cGUsIHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8aW50LExJKzE+KCkpOwogICAgfQogICAgZnVuY190eXBlIGZ1bmM7CnB1YmxpYzoKICAgIGV4cGxpY2l0IGRvdWJsZV9kaXNwYXRjaChmdW5jX3R5cGUgZnVuYykgOiBmdW5jKGZ1bmMpIHt9CgogICAgcmV0dXJuX3R5cGUgb3BlcmF0b3IoKShMQmFzZSogbCwgUkJhc2UqIHIpIAogICAge3JldHVybiBpdGVyX2xlZnRfdHlwZXMobCwgciwgdHlwZWlkKCpsKSwgc3RkOjppbnRlZ3JhbF9jb25zdGFudDxpbnQsMD4oKSk7fQogICAgCiAgICByZXR1cm5fdHlwZSBkaXNwYXRjaChMQmFzZSogbCwgUkJhc2UqIHIpIAogICAge3JldHVybiBpdGVyX2xlZnRfdHlwZXMobCwgciwgdHlwZWlkKCpsKSwgc3RkOjppbnRlZ3JhbF9jb25zdGFudDxpbnQsMD4oKSk7fQp9OwojZGVmaW5lIERPVUJMRV9ESVNQQVRDSEVSKEZVTkMpIFwKc3RydWN0IHtcCiAgICB0ZW1wbGF0ZTxjbGFzcyBMLGNsYXNzIFI+IFwKICAgIGF1dG8gb3BlcmF0b3IoKShMJiYgbCwgUiYmIHIpIFwKICAgIC0+ZGVjbHR5cGUoRlVOQyhzdGQ6OmZvcndhcmQ8TD4obCksc3RkOjpmb3J3YXJkPFI+KHIpKSkgXAogICAge3JldHVybiBGVU5DKHN0ZDo6Zm9yd2FyZDxMPihsKSxzdGQ6OmZvcndhcmQ8Uj4ocikpO30gXAp9CgoKCiNpbmNsdWRlIDxpb3N0cmVhbT4Kc3RydWN0IExvdWQgewogICAgTG91ZCgpIHtzdGQ6OmNlcnIgPDwgIkxPVUQ6IGRlZmF1bHQgY3RvclxuIjt9CiAgICBMb3VkKGNvbnN0IExvdWQmKSB7c3RkOjpjZXJyIDw8ICJMT1VEOiBjb3B5IGN0b3JcbiI7fQogICAgTG91ZChMb3VkJiYpIHtzdGQ6OmNlcnIgPDwgIkxPVUQ6IG1vdmUgY3RvclxuIjt9CiAgICB+TG91ZCgpIHtzdGQ6OmNlcnIgPDwgIkxPVUQ6IGR0b3JcbiI7fQogICAgTG91ZCYgb3BlcmF0b3I9KGNvbnN0IExvdWQmKSB7c3RkOjpjZXJyIDw8ICJMT1VEOiBjb3B5IGFzc2lnblxuIjsgcmV0dXJuICp0aGlzO30KICAgIExvdWQmIG9wZXJhdG9yPShMb3VkJiYpIHtzdGQ6OmNlcnIgPDwgIkxPVUQ6IG1vdmUgYXNzaWduXG4iOyByZXR1cm4gKnRoaXM7fQp9OwpzdHJ1Y3QgTGV0dGVyIHsKICAgIHZpcnR1YWwgfkxldHRlcigpIHt9Cn07CnN0cnVjdCBBIDogcHVibGljIExldHRlciB7fTsKc3RydWN0IEIgOiBwdWJsaWMgTGV0dGVyIHt9OwpzdHJ1Y3QgQyA6IHB1YmxpYyBMZXR0ZXIge307CnN0cnVjdCBOdW1iZXIgewogICAgdmlydHVhbCB+TnVtYmVyKCkge30KfTsKc3RydWN0IE9uZSA6IHB1YmxpYyBOdW1iZXIge307CnN0cnVjdCBUd28gOiBwdWJsaWMgTnVtYmVyIHt9OwpzdHJ1Y3QgVGhyZWUgOiBwdWJsaWMgTnVtYmVyIHt9OwoKTG91ZCBwcmludChjb25zdCBBKixjb25zdCBPbmUqKSAgICAge3N0ZDo6Y2VyciA8PCAiQTFcbiI7IHJldHVybiB7fTt9CkxvdWQgcHJpbnQoY29uc3QgQSosY29uc3QgVHdvKikgICAgIHtzdGQ6OmNlcnIgPDwgIkEyXG4iOyByZXR1cm4ge307fQpMb3VkIHByaW50KGNvbnN0IEEqLGNvbnN0IFRocmVlKikgICB7c3RkOjpjZXJyIDw8ICJBM1xuIjsgcmV0dXJuIHt9O30KTG91ZCBwcmludChjb25zdCBCKixjb25zdCBPbmUqKSAgICAge3N0ZDo6Y2VyciA8PCAiQjFcbiI7IHJldHVybiB7fTt9CkxvdWQgcHJpbnQoY29uc3QgQiosY29uc3QgVHdvKikgICAgIHtzdGQ6OmNlcnIgPDwgIkIyXG4iOyByZXR1cm4ge307fQpMb3VkIHByaW50KGNvbnN0IEIqLGNvbnN0IFRocmVlKikgICB7c3RkOjpjZXJyIDw8ICJCM1xuIjsgcmV0dXJuIHt9O30KTG91ZCBwcmludChjb25zdCBDKixjb25zdCBPbmUqKSAgICAge3N0ZDo6Y2VyciA8PCAiQzFcbiI7IHJldHVybiB7fTt9CkxvdWQgcHJpbnQoY29uc3QgQyosY29uc3QgVHdvKikgICAgIHtzdGQ6OmNlcnIgPDwgIkMyXG4iOyByZXR1cm4ge307fQpMb3VkIHByaW50KGNvbnN0IEMqLGNvbnN0IFRocmVlKikgICB7c3RkOjpjZXJyIDw8ICJDM1xuIjsgcmV0dXJuIHt9O30KRE9VQkxFX0RJU1BBVENIRVIocHJpbnQpIHByaW50ZGlzcGF0Y2g7CmRvdWJsZV9kaXNwYXRjaDxkZWNsdHlwZShwcmludGRpc3BhdGNoKSwgY29uc3QgTGV0dGVyLCBjb25zdCBOdW1iZXIsIAogICAgc3RkOjp0dXBsZTxjb25zdCBBLGNvbnN0IEIsY29uc3QgQz4sCiAgICBzdGQ6OnR1cGxlPGNvbnN0IE9uZSxjb25zdCBUd28sY29uc3QgVGhyZWU+PiAKICAgIGRfZGlzcGF0Y2hlcihwcmludGRpc3BhdGNoKTsKICAgIAppbnQgbWFpbigpIAp7CiAgICBjb25zdCBMZXR0ZXImIGEgPSBBe307CiAgICBjb25zdCBMZXR0ZXImIGIgPSBCe307CiAgICBjb25zdCBMZXR0ZXImIGMgPSBDe307CiAgICBjb25zdCBOdW1iZXImIG9uID0gT25le307CiAgICBjb25zdCBOdW1iZXImIHR3ID0gVHdve307CiAgICBjb25zdCBOdW1iZXImIHRoID0gVGhyZWV7fTsKCiAgICBkX2Rpc3BhdGNoZXIoJmEsJm9uKTsKICAgIGRfZGlzcGF0Y2hlcigmYSwmdHcpOwogICAgZF9kaXNwYXRjaGVyKCZhLCZ0aCk7CiAgICBkX2Rpc3BhdGNoZXIoJmIsJm9uKTsKICAgIGRfZGlzcGF0Y2hlcigmYiwmdHcpOwogICAgZF9kaXNwYXRjaGVyKCZiLCZ0aCk7CiAgICBkX2Rpc3BhdGNoZXIoJmMsJm9uKTsKICAgIGRfZGlzcGF0Y2hlcigmYywmdHcpOwogICAgZF9kaXNwYXRjaGVyKCZjLCZ0aCk7CgogICAgcmV0dXJuIDA7Cn0=