Electorat

generic_visitor.cpp

Dec 12th, 2021 (edited)
410
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.86 KB | None | 0 0
  1. #include <vector>
  2. #include <iostream>
  3. #include <concepts>
  4. #include <type_traits>
  5.  
  6.  
  7. // Util
  8.  
  9. template<typename T, template<typename...> typename TTemplate >
  10. struct is_specialization : std::false_type { };
  11.  
  12. template<template<typename...> typename Template, typename... TArgs>
  13. struct is_specialization<Template<TArgs...>, Template> : std::true_type { };
  14.  
  15. template<typename T, template<typename...> typename Template>
  16. constexpr bool is_specialization_v = is_specialization<T, Template>::value;
  17.  
  18. template<typename T, template<typename...> typename Template>
  19. concept specialization = is_specialization_v<T, Template>;
  20.  
  21. // Visitor
  22.  
  23. namespace visitor
  24. {
  25.     template<typename T, std::invocable<const T&> F>
  26.     struct when_t {
  27.         using value_t = T;
  28.         F f;
  29.     };
  30.  
  31.     template<typename T, std::invocable<const T&> F>
  32.     constexpr when_t<T, F> when(F&& f) {
  33.         return when_t<T, F>{ std::forward<F>(f) };
  34.     }
  35.  
  36.  
  37.     template<std::invocable<> F>
  38.     struct when_unknown_t {
  39.         F f;
  40.  
  41.         bool operator()() const {
  42.             f();
  43.             return true;
  44.         }    
  45.     };
  46.  
  47.     template<std::invocable<> F>
  48.     constexpr when_unknown_t<F> when_unknown(F&& f) {
  49.         return when_unknown_t<F>{ std::forward<F>(f) };
  50.     }
  51.  
  52.     template<typename Base, std::invocable<> Fo, specialization<when_t>... Ws>
  53.     auto make(const when_unknown_t<Fo>& whenunk, Ws&&... whens) {
  54.         constexpr auto make_impl = []<std::derived_from<Base> T>(const Base* t, std::invocable<const T&> auto&& f){
  55.             const T* tc = dynamic_cast<const T*>(t);
  56.             if(tc == nullptr) {
  57.                 return false;
  58.             }
  59.             f(*tc);
  60.             return true;
  61.         };
  62.        
  63.         return [&make_impl, &whenunk, ...whens = std::forward<Ws>(whens)](const Base& t){
  64.             (make_impl.template operator()<typename Ws::value_t>(&t, whens.f) || ... || whenunk());
  65.         };
  66.     }
  67.  
  68. }
  69.  
  70.  
  71. // Example
  72.  
  73. struct Token {
  74.     virtual ~Token() {}
  75. };
  76.  
  77. struct Optok : Token {
  78.     void optok() const { std::cout << "optok\n"; }
  79. };
  80.  
  81. struct Litok : Token {
  82.     void litok() const { std::cout << "litok\n"; }
  83. };
  84.  
  85. struct Vatok : Token {
  86.     void vatok() const { std::cout << "vatok\n"; }
  87. };
  88.  
  89. struct Hztok : Token {};
  90.  
  91. int main() {
  92.     std::vector<Token*> toks(4);
  93.     toks[0] = new Vatok;
  94.     toks[1] = new Litok;
  95.     toks[2] = new Optok;
  96.     toks[3] = new Hztok;
  97.  
  98.     auto token_visitor = visitor::make<Token>(
  99.         visitor::when_unknown([](){ std::cout << "unknown\n"; }),
  100.         visitor::when<Optok>([](const Optok& op){ op.optok(); }),
  101.         visitor::when<Litok>([](const Litok& li){ li.litok(); }),
  102.         visitor::when<Vatok>([](const Vatok& va){ va.vatok(); })
  103.     );
  104.     for(auto tok : toks)
  105.         token_visitor(*tok);
  106.  
  107.     return 0;
  108. }
  109.  
  110. // output:
  111.  
  112. // vatok
  113. // litok
  114. // optok
  115. // unknown
Add Comment
Please, Sign In to add comment