#include <utility>
#include <cstddef>
#include <iostream>
using namespace std;
struct Triangle;
struct Square;
struct PolygonVisitor
{
virtual ~PolygonVisitor() {}
virtual void visit(Triangle& tr) = 0;
virtual void visit(Square& sq) = 0;
};
struct Polygon
{
virtual void accept(PolygonVisitor& v) = 0;
};
struct Triangle : Polygon
{
void accept(PolygonVisitor& v) override
{
v.visit(*this);
}
};
struct Square : Polygon
{
void accept(PolygonVisitor& v) override
{
v.visit(*this);
}
};
template <typename T,
typename F,
typename BaseInner,
typename ArgsT>
struct ComposeVisitor
{
struct Inner : public BaseInner
{
using BaseInner::visit;
Inner(ArgsT&& args) :
BaseInner(move(args.second)),
m_f(move(args.first))
{
}
void visit(T& t) final override
{
m_f(t);
}
private:
F m_f;
};
ComposeVisitor(ArgsT&& args) :
m_args(move(args))
{
}
template <typename Tadd,
typename Fadd>
ComposeVisitor <
Tadd,
Fadd,
Inner,
pair < Fadd, ArgsT >> on(Fadd&& f)
{
return ComposeVisitor <
Tadd,
Fadd,
Inner,
pair < Fadd, ArgsT >> (
make_pair(
move(f),
move(m_args)));
}
Inner end_visitor()
{
return Inner(move(m_args));
}
ArgsT m_args;
};
template <typename TVisitorBase>
struct EmptyVisitor
{
struct Inner : public TVisitorBase
{
using TVisitorBase::visit;
Inner(nullptr_t) {}
};
template <typename Tadd, typename Fadd>
ComposeVisitor <
Tadd,
Fadd,
Inner,
pair < Fadd, nullptr_t >> on(Fadd&& f)
{
return ComposeVisitor <
Tadd,
Fadd,
Inner,
pair < Fadd, nullptr_t >> (
make_pair(
move(f),
nullptr));
}
};
template <typename TVisitorBase>
EmptyVisitor<TVisitorBase> begin_visitor()
{
return EmptyVisitor<TVisitorBase>();
}
int main()
{
int sides = 0;
auto v = begin_visitor<PolygonVisitor>()
.on<Triangle>([&sides](Triangle&)
{
sides = 3;
})
.on<Square>([&sides](Square&)
{
sides = 4;
})
.end_visitor();
Triangle p;
p.accept(v);
std::cout << "sides: " << sides << std::endl;
}
I2luY2x1ZGUgPHV0aWxpdHk+CiNpbmNsdWRlIDxjc3RkZGVmPgojaW5jbHVkZSA8aW9zdHJlYW0+Cgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKc3RydWN0IFRyaWFuZ2xlOwpzdHJ1Y3QgU3F1YXJlOwoKc3RydWN0IFBvbHlnb25WaXNpdG9yCnsKICAgIHZpcnR1YWwgflBvbHlnb25WaXNpdG9yKCkge30KCiAgICB2aXJ0dWFsIHZvaWQgdmlzaXQoVHJpYW5nbGUmIHRyKSA9IDA7CiAgICB2aXJ0dWFsIHZvaWQgdmlzaXQoU3F1YXJlJiBzcSkgPSAwOwp9OwoKc3RydWN0IFBvbHlnb24KewogICAgdmlydHVhbCB2b2lkIGFjY2VwdChQb2x5Z29uVmlzaXRvciYgdikgPSAwOwp9OwoKc3RydWN0IFRyaWFuZ2xlIDogUG9seWdvbgp7CiAgICB2b2lkIGFjY2VwdChQb2x5Z29uVmlzaXRvciYgdikgb3ZlcnJpZGUKICAgIHsKICAgICAgICB2LnZpc2l0KCp0aGlzKTsKICAgIH0KfTsKCnN0cnVjdCBTcXVhcmUgOiBQb2x5Z29uCnsKICAgIHZvaWQgYWNjZXB0KFBvbHlnb25WaXNpdG9yJiB2KSBvdmVycmlkZQogICAgewogICAgICAgIHYudmlzaXQoKnRoaXMpOwogICAgfQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFQsCiAgICB0eXBlbmFtZSBGLAogICAgdHlwZW5hbWUgQmFzZUlubmVyLAogICAgdHlwZW5hbWUgQXJnc1Q+CnN0cnVjdCBDb21wb3NlVmlzaXRvcgp7CiAgICBzdHJ1Y3QgSW5uZXIgOiBwdWJsaWMgQmFzZUlubmVyCiAgICB7CiAgICAgICAgdXNpbmcgQmFzZUlubmVyOjp2aXNpdDsKICAgICAgICBJbm5lcihBcmdzVCYmIGFyZ3MpIDoKICAgICAgICAgICAgQmFzZUlubmVyKG1vdmUoYXJncy5zZWNvbmQpKSwKICAgICAgICAgICAgbV9mKG1vdmUoYXJncy5maXJzdCkpCiAgICAgICAgewogICAgICAgIH0KICAgICAgICB2b2lkIHZpc2l0KFQmIHQpIGZpbmFsIG92ZXJyaWRlCiAgICAgICAgewogICAgICAgICAgICBtX2YodCk7CiAgICAgICAgfQogICAgcHJpdmF0ZToKICAgICAgICBGIG1fZjsKICAgIH07CiAgICBDb21wb3NlVmlzaXRvcihBcmdzVCYmIGFyZ3MpIDoKICAgICAgICBtX2FyZ3MobW92ZShhcmdzKSkKICAgIHsKICAgIH0KICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUYWRkLAogICAgICAgIHR5cGVuYW1lIEZhZGQ+CiAgICAgICAgQ29tcG9zZVZpc2l0b3IgPAogICAgICAgIFRhZGQsCiAgICAgICAgRmFkZCwKICAgICAgICBJbm5lciwKICAgICAgICBwYWlyIDwgRmFkZCwgQXJnc1QgPj4gb24oRmFkZCYmIGYpCiAgICB7CiAgICAgICAgcmV0dXJuIENvbXBvc2VWaXNpdG9yIDwKICAgICAgICAgICAgVGFkZCwKICAgICAgICAgICAgRmFkZCwKICAgICAgICAgICAgSW5uZXIsCiAgICAgICAgICAgIHBhaXIgPCBGYWRkLCBBcmdzVCA+PiAoCiAgICAgICAgICAgIG1ha2VfcGFpcigKICAgICAgICAgICAgbW92ZShmKSwKICAgICAgICAgICAgbW92ZShtX2FyZ3MpKSk7CiAgICB9CiAgICBJbm5lciBlbmRfdmlzaXRvcigpCiAgICB7CiAgICAgICAgcmV0dXJuIElubmVyKG1vdmUobV9hcmdzKSk7CiAgICB9CgogICAgQXJnc1QgbV9hcmdzOwp9Owp0ZW1wbGF0ZSA8dHlwZW5hbWUgVFZpc2l0b3JCYXNlPgpzdHJ1Y3QgRW1wdHlWaXNpdG9yCnsKICAgIHN0cnVjdCBJbm5lciA6IHB1YmxpYyBUVmlzaXRvckJhc2UKICAgIHsKICAgICAgICB1c2luZyBUVmlzaXRvckJhc2U6OnZpc2l0OwogICAgICAgIElubmVyKG51bGxwdHJfdCkge30KICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRhZGQsIHR5cGVuYW1lIEZhZGQ+CiAgICBDb21wb3NlVmlzaXRvciA8CiAgICAgICAgVGFkZCwKICAgICAgICBGYWRkLAogICAgICAgIElubmVyLAogICAgICAgIHBhaXIgPCBGYWRkLCBudWxscHRyX3QgPj4gb24oRmFkZCYmIGYpCiAgICB7CiAgICAgICAgcmV0dXJuIENvbXBvc2VWaXNpdG9yIDwKICAgICAgICAgICAgVGFkZCwKICAgICAgICAgICAgRmFkZCwKICAgICAgICAgICAgSW5uZXIsCiAgICAgICAgICAgIHBhaXIgPCBGYWRkLCBudWxscHRyX3QgPj4gKAogICAgICAgICAgICBtYWtlX3BhaXIoCiAgICAgICAgICAgIG1vdmUoZiksCiAgICAgICAgICAgIG51bGxwdHIpKTsKICAgIH0KfTsKdGVtcGxhdGUgPHR5cGVuYW1lIFRWaXNpdG9yQmFzZT4KRW1wdHlWaXNpdG9yPFRWaXNpdG9yQmFzZT4gYmVnaW5fdmlzaXRvcigpCnsKICAgIHJldHVybiBFbXB0eVZpc2l0b3I8VFZpc2l0b3JCYXNlPigpOwp9CgppbnQgbWFpbigpCnsKICAgIGludCBzaWRlcyA9IDA7CgogICAgYXV0byB2ID0gYmVnaW5fdmlzaXRvcjxQb2x5Z29uVmlzaXRvcj4oKQogICAgICAgIC5vbjxUcmlhbmdsZT4oWyZzaWRlc10oVHJpYW5nbGUmKQogICAgewogICAgICAgIHNpZGVzID0gMzsKICAgIH0pCiAgICAgICAgLm9uPFNxdWFyZT4oWyZzaWRlc10oU3F1YXJlJikKICAgIHsKICAgICAgICBzaWRlcyA9IDQ7CiAgICB9KQogICAgICAgIC5lbmRfdmlzaXRvcigpOwoKICAgIFRyaWFuZ2xlIHA7CiAgICBwLmFjY2VwdCh2KTsKCiAgICBzdGQ6OmNvdXQgPDwgInNpZGVzOiAiIDw8IHNpZGVzIDw8IHN0ZDo6ZW5kbDsKfQo=
prog.cpp: In instantiation of ‘struct ComposeVisitor<Triangle, main()::__lambda0, EmptyVisitor<PolygonVisitor>::Inner, std::pair<main()::__lambda0, std::nullptr_t> >::Inner’:
prog.cpp:45:12: required from ‘struct ComposeVisitor<Square, main()::__lambda1, ComposeVisitor<Triangle, main()::__lambda0, EmptyVisitor<PolygonVisitor>::Inner, std::pair<main()::__lambda0, std::nullptr_t> >::Inner, std::pair<main()::__lambda1, std::pair<main()::__lambda0, std::nullptr_t> > >::Inner’
prog.cpp:133:22: required from here
prog.cpp:81:11: error: cannot allocate an object of abstract type ‘ComposeVisitor<Triangle, main()::__lambda0, EmptyVisitor<PolygonVisitor>::Inner, std::pair<main()::__lambda0, std::nullptr_t> >::Inner’
Inner end_visitor()
^
prog.cpp:45:12: note: because the following virtual functions are pure within ‘ComposeVisitor<Triangle, main()::__lambda0, EmptyVisitor<PolygonVisitor>::Inner, std::pair<main()::__lambda0, std::nullptr_t> >::Inner’:
struct Inner : public BaseInner
^
prog.cpp:15:18: note: virtual void PolygonVisitor::visit(Square&)
virtual void visit(Square& sq) = 0;
^