#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;
template<typename Derived>
class BaseData {
public:
template<typename Visitor>
void accept(Visitor &v){
static_cast<Derived*>(this)->accept(v);
}
};
class DerivedBaseData1: BaseData<DerivedBaseData1> {
public:
template<typename Visitor>
void accept(Visitor &v){
std::cout << "DerivedBaseData1: accepting visitor " << v << std::endl;
}
};
class DerivedBaseData2: BaseData<DerivedBaseData2> {
public:
template<typename Visitor>
void accept(Visitor &v){
std::cout << "DerivedBaseData2: accepting visitor " << v << std::endl;
}
};
namespace impl {
template <size_t N>
struct num2type {};
template <size_t Idx, typename T, typename Visitor>
void accept_impl(Visitor &v, T &&collection, num2type<Idx>) {
// run accept on current object
auto &object = std::get<Idx>(collection);
object.accept(v);
// move iteration forward
accept_impl(v, std::forward<T>(collection), num2type<Idx - 1>{});
}
template <typename T, typename Visitor>
void accept_impl(Visitor &v, T &&collection, num2type<0>) {
// run accept on current object
auto &object = std::get<0>(collection);
object.accept(v);
}
}
template<typename ...Ts, typename Visitor>
void accept(Visitor &v, std::tuple<Ts...> &&collection) {
using T = decltype(collection);
impl::accept_impl(v, std::forward<T>(collection), impl::num2type<std::tuple_size<std::decay_t<T>>::value - 1>{});
}
int main() {
using visitor_type = int;
visitor_type visitor = 42;
DerivedBaseData1 a1, a3;
DerivedBaseData2 a2;
accept(visitor, std::tie(a1, a2, a3));
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHVwbGU+CiNpbmNsdWRlIDx0eXBlX3RyYWl0cz4KdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCgp0ZW1wbGF0ZTx0eXBlbmFtZSBEZXJpdmVkPgpjbGFzcyBCYXNlRGF0YSB7CnB1YmxpYzoKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFZpc2l0b3I+CiAgICB2b2lkIGFjY2VwdChWaXNpdG9yICZ2KXsKICAgICAgICAgc3RhdGljX2Nhc3Q8RGVyaXZlZCo+KHRoaXMpLT5hY2NlcHQodik7CiAgICB9Cn07CgpjbGFzcyBEZXJpdmVkQmFzZURhdGExOiBCYXNlRGF0YTxEZXJpdmVkQmFzZURhdGExPiB7CnB1YmxpYzoKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFZpc2l0b3I+CiAgICB2b2lkIGFjY2VwdChWaXNpdG9yICZ2KXsKICAgIAlzdGQ6OmNvdXQgPDwgIkRlcml2ZWRCYXNlRGF0YTE6IGFjY2VwdGluZyB2aXNpdG9yICIgPDwgdiA8PCBzdGQ6OmVuZGw7CiAgICB9ICAgIAp9OwpjbGFzcyBEZXJpdmVkQmFzZURhdGEyOiBCYXNlRGF0YTxEZXJpdmVkQmFzZURhdGEyPiB7CnB1YmxpYzoKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFZpc2l0b3I+CiAgICB2b2lkIGFjY2VwdChWaXNpdG9yICZ2KXsKICAgIAlzdGQ6OmNvdXQgPDwgIkRlcml2ZWRCYXNlRGF0YTI6IGFjY2VwdGluZyB2aXNpdG9yICIgPDwgdiA8PCBzdGQ6OmVuZGw7CiAgICB9ICAgIAp9OwoKbmFtZXNwYWNlIGltcGwgewoJCQoJdGVtcGxhdGUgPHNpemVfdCBOPiAKCXN0cnVjdCBudW0ydHlwZSB7fTsKCQoJdGVtcGxhdGUgPHNpemVfdCBJZHgsIHR5cGVuYW1lIFQsIHR5cGVuYW1lIFZpc2l0b3I+Cgl2b2lkIGFjY2VwdF9pbXBsKFZpc2l0b3IgJnYsIFQgJiZjb2xsZWN0aW9uLCBudW0ydHlwZTxJZHg+KSB7CgkJLy8gcnVuIGFjY2VwdCBvbiBjdXJyZW50IG9iamVjdAoJCWF1dG8gJm9iamVjdCA9IHN0ZDo6Z2V0PElkeD4oY29sbGVjdGlvbik7CgkJb2JqZWN0LmFjY2VwdCh2KTsKCQkvLyBtb3ZlIGl0ZXJhdGlvbiBmb3J3YXJkCgkJYWNjZXB0X2ltcGwodiwgc3RkOjpmb3J3YXJkPFQ+KGNvbGxlY3Rpb24pLCBudW0ydHlwZTxJZHggLSAxPnt9KTsKCX0KCQoJdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFZpc2l0b3I+Cgl2b2lkIGFjY2VwdF9pbXBsKFZpc2l0b3IgJnYsIFQgJiZjb2xsZWN0aW9uLCBudW0ydHlwZTwwPikgewoJCS8vIHJ1biBhY2NlcHQgb24gY3VycmVudCBvYmplY3QKCQlhdXRvICZvYmplY3QgPSBzdGQ6OmdldDwwPihjb2xsZWN0aW9uKTsKCQlvYmplY3QuYWNjZXB0KHYpOwoJfQp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSAuLi5UcywgdHlwZW5hbWUgVmlzaXRvcj4Kdm9pZCBhY2NlcHQoVmlzaXRvciAmdiwgc3RkOjp0dXBsZTxUcy4uLj4gJiZjb2xsZWN0aW9uKSB7Cgl1c2luZyBUID0gZGVjbHR5cGUoY29sbGVjdGlvbik7CglpbXBsOjphY2NlcHRfaW1wbCh2LCBzdGQ6OmZvcndhcmQ8VD4oY29sbGVjdGlvbiksIGltcGw6Om51bTJ0eXBlPHN0ZDo6dHVwbGVfc2l6ZTxzdGQ6OmRlY2F5X3Q8VD4+Ojp2YWx1ZSAtIDE+e30pOwp9CgoKaW50IG1haW4oKSB7Cgl1c2luZyB2aXNpdG9yX3R5cGUgPSBpbnQ7Cgl2aXNpdG9yX3R5cGUgdmlzaXRvciA9IDQyOwoKCURlcml2ZWRCYXNlRGF0YTEgYTEsIGEzOwoJRGVyaXZlZEJhc2VEYXRhMiBhMjsKCWFjY2VwdCh2aXNpdG9yLCBzdGQ6OnRpZShhMSwgYTIsIGEzKSk7CgkKCXJldHVybiAwOwp9