fork download
  1. #include <iostream>
  2. #include <tuple>
  3. #include <type_traits>
  4. using namespace std;
  5.  
  6.  
  7. template<typename Derived>
  8. class BaseData {
  9. public:
  10. template<typename Visitor>
  11. void accept(Visitor &v){
  12. static_cast<Derived*>(this)->accept(v);
  13. }
  14. };
  15.  
  16. class DerivedBaseData1: BaseData<DerivedBaseData1> {
  17. public:
  18. template<typename Visitor>
  19. void accept(Visitor &v){
  20. std::cout << "DerivedBaseData1: accepting visitor " << v << std::endl;
  21. }
  22. };
  23. class DerivedBaseData2: BaseData<DerivedBaseData2> {
  24. public:
  25. template<typename Visitor>
  26. void accept(Visitor &v){
  27. std::cout << "DerivedBaseData2: accepting visitor " << v << std::endl;
  28. }
  29. };
  30.  
  31. namespace impl {
  32.  
  33. template <size_t N>
  34. struct num2type {};
  35.  
  36. template <size_t Idx, typename T, typename Visitor>
  37. void accept_impl(Visitor &v, T &&collection, num2type<Idx>) {
  38. // run accept on current object
  39. auto &object = std::get<Idx>(collection);
  40. object.accept(v);
  41. // move iteration forward
  42. accept_impl(v, std::forward<T>(collection), num2type<Idx - 1>{});
  43. }
  44.  
  45. template <typename T, typename Visitor>
  46. void accept_impl(Visitor &v, T &&collection, num2type<0>) {
  47. // run accept on current object
  48. auto &object = std::get<0>(collection);
  49. object.accept(v);
  50. }
  51. }
  52.  
  53. template<typename ...Ts, typename Visitor>
  54. void accept(Visitor &v, std::tuple<Ts...> &&collection) {
  55. using T = decltype(collection);
  56. impl::accept_impl(v, std::forward<T>(collection), impl::num2type<std::tuple_size<std::decay_t<T>>::value - 1>{});
  57. }
  58.  
  59.  
  60. int main() {
  61. using visitor_type = int;
  62. visitor_type visitor = 42;
  63.  
  64. DerivedBaseData1 a1, a3;
  65. DerivedBaseData2 a2;
  66. accept(visitor, std::tie(a1, a2, a3));
  67.  
  68. return 0;
  69. }
Success #stdin #stdout 0s 3460KB
stdin
Standard input is empty
stdout
DerivedBaseData1: accepting visitor 42
DerivedBaseData2: accepting visitor 42
DerivedBaseData1: accepting visitor 42