fork download
  1. #include <iostream>
  2. #include <string>
  3. #include <memory>
  4. #include <type_traits>
  5.  
  6. class TimeDisplay {
  7. public:
  8. enum Mode {ClockTime12Hours, ClockTime24Hours, DescriptiveTime, CrazyDescriptiveTime, NumTimeDiplayModes};
  9. virtual ~TimeDisplay() = default;
  10. virtual std::string tell() const = 0;
  11. virtual std::string tellMaybeWithPeriod() const = 0;
  12. };
  13.  
  14. template <typename> class TimeDisplayCRTP;
  15. template <TimeDisplay::Mode, bool = false> class TimeDisplayClass;
  16.  
  17. template <TimeDisplay::Mode M, bool B>
  18. class TimeDisplayCRTP<TimeDisplayClass<M, B>> : virtual public TimeDisplay {
  19. virtual std::string tellMaybeWithPeriod() const override {return tell() + (B ? "." : "");}
  20. };
  21.  
  22. template <bool B>
  23. class TimeDisplayClass<TimeDisplay::ClockTime12Hours, B> : public TimeDisplayCRTP<TimeDisplayClass<TimeDisplay::ClockTime12Hours, B>> {
  24. virtual std::string tell() const override {return "6:30 pm";}
  25. };
  26.  
  27. template <bool B>
  28. class TimeDisplayClass<TimeDisplay::ClockTime24Hours, B> : public TimeDisplayCRTP<TimeDisplayClass<TimeDisplay::ClockTime24Hours, B>> {
  29. virtual std::string tell() const override {return "18:30";}
  30. };
  31.  
  32. template <bool B>
  33. class TimeDisplayClass<TimeDisplay::DescriptiveTime, B> : public TimeDisplayCRTP<TimeDisplayClass<TimeDisplay::DescriptiveTime, B>> {
  34. virtual std::string tell() const override {return "evening";}
  35. };
  36.  
  37. template <bool B>
  38. class TimeDisplayClass<TimeDisplay::CrazyDescriptiveTime, B> : public TimeDisplayCRTP<TimeDisplayClass<TimeDisplay::CrazyDescriptiveTime, B>> {
  39. virtual std::string tell() const override {return "evening (for many it is dinner time, but many eat dinner later)";}
  40. };
  41.  
  42. class System {
  43. public:
  44. enum Action {DisplayTime, Foo, Bar, Baz};
  45. private:
  46. template <Action, int> struct SetTimeDisplay;
  47. static std::unique_ptr<TimeDisplay> timeDisplay;
  48. public:
  49. static std::string timeAsString() {return timeDisplay->tell();}
  50. static std::string timeAsStringMaybeWithPeriod() {return timeDisplay->tellMaybeWithPeriod();}
  51. template <Action> static inline void action (TimeDisplay::Mode);
  52. private:
  53. template <Action> static inline void finalAction();
  54. };
  55. std::unique_ptr<TimeDisplay> System::timeDisplay;
  56.  
  57. template <System::Action, TimeDisplay::Mode> struct PeriodOrNoPeriod;
  58.  
  59. template <> struct PeriodOrNoPeriod<System::DisplayTime, TimeDisplay::ClockTime12Hours> : std::false_type {};
  60. template <> struct PeriodOrNoPeriod<System::DisplayTime, TimeDisplay::ClockTime24Hours> : std::false_type {};
  61. template <> struct PeriodOrNoPeriod<System::DisplayTime, TimeDisplay::DescriptiveTime> : std::true_type {};
  62. template <> struct PeriodOrNoPeriod<System::DisplayTime, TimeDisplay::CrazyDescriptiveTime> : std::true_type {};
  63.  
  64. template <> struct PeriodOrNoPeriod<System::Foo, TimeDisplay::ClockTime12Hours> : std::false_type {};
  65. template <> struct PeriodOrNoPeriod<System::Foo, TimeDisplay::ClockTime24Hours> : std::true_type {};
  66. template <> struct PeriodOrNoPeriod<System::Foo, TimeDisplay::DescriptiveTime> : std::true_type {};
  67. template <> struct PeriodOrNoPeriod<System::Foo, TimeDisplay::CrazyDescriptiveTime> : std::false_type {};
  68.  
  69. template <> struct PeriodOrNoPeriod<System::Bar, TimeDisplay::ClockTime12Hours> : std::true_type {};
  70. template <> struct PeriodOrNoPeriod<System::Bar, TimeDisplay::ClockTime24Hours> : std::true_type {};
  71. template <> struct PeriodOrNoPeriod<System::Bar, TimeDisplay::DescriptiveTime> : std::false_type {};
  72. template <> struct PeriodOrNoPeriod<System::Bar, TimeDisplay::CrazyDescriptiveTime> : std::true_type {};
  73.  
  74. template <> struct PeriodOrNoPeriod<System::Baz, TimeDisplay::ClockTime12Hours> : std::false_type {};
  75. template <> struct PeriodOrNoPeriod<System::Baz, TimeDisplay::ClockTime24Hours> : std::true_type {};
  76. template <> struct PeriodOrNoPeriod<System::Baz, TimeDisplay::DescriptiveTime> : std::false_type {};
  77. template <> struct PeriodOrNoPeriod<System::Baz, TimeDisplay::CrazyDescriptiveTime> : std::false_type {};
  78.  
  79. template <System::Action A, int N>
  80. struct System::SetTimeDisplay {
  81. static void execute (TimeDisplay::Mode mode) {
  82. constexpr TimeDisplay::Mode M = static_cast<TimeDisplay::Mode>(N);
  83. if (mode == M)
  84. timeDisplay = std::make_unique<TimeDisplayClass<M, PeriodOrNoPeriod<A,M>::value>>(); // 'timeDisplay' is a static data member of System, so System::SetTimeDisplay<A,N> has access to it.
  85. else
  86. SetTimeDisplay<A, N+1>::execute(mode);
  87. }
  88. };
  89.  
  90. template <System::Action A>
  91. struct System::SetTimeDisplay<A, TimeDisplay::NumTimeDiplayModes> {
  92. static void execute (TimeDisplay::Mode) {std::cout << "Error! End of recursion reached.\n";}
  93. };
  94.  
  95. template <System::Action A>
  96. inline void System::action (TimeDisplay::Mode mode) {
  97. SetTimeDisplay<A,0>::execute(mode); // Template recursion.
  98. finalAction<A>();
  99. }
  100.  
  101. template <>
  102. inline void System::finalAction<System::DisplayTime>() {std::cout << "Current time: " << timeDisplay->tellMaybeWithPeriod() << '\n';}
  103.  
  104. template <>
  105. inline void System::finalAction<System::Foo>() {std::cout << "Foo: " << timeDisplay->tellMaybeWithPeriod() << '\n';}
  106.  
  107. template <>
  108. inline void System::finalAction<System::Bar>() {std::cout << "Bar: " << timeDisplay->tellMaybeWithPeriod() << '\n';}
  109.  
  110. template <>
  111. inline void System::finalAction<System::Baz>() {std::cout << "Baz: " << timeDisplay->tellMaybeWithPeriod() << '\n';}
  112.  
  113. int main() {
  114. for (int i = 0; i < TimeDisplay::NumTimeDiplayModes; i++)
  115. System::action<System::DisplayTime>(static_cast<TimeDisplay::Mode>(i)); // System::displayCurrentTime is now just one of the specializations of System::action<A>. The other specializations are below.
  116. std::cout << "-----------------------------------------------------------------------------\n";
  117. for (int i = 0; i < TimeDisplay::NumTimeDiplayModes; i++)
  118. System::action<System::Foo>(static_cast<TimeDisplay::Mode>(i));
  119. std::cout << "-----------------------------------------------------------------------------\n";
  120. for (int i = 0; i < TimeDisplay::NumTimeDiplayModes; i++)
  121. System::action<System::Bar>(static_cast<TimeDisplay::Mode>(i));
  122. std::cout << "-----------------------------------------------------------------------------\n";
  123. for (int i = 0; i < TimeDisplay::NumTimeDiplayModes; i++)
  124. System::action<System::Baz>(static_cast<TimeDisplay::Mode>(i));
  125. }
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
Current time: 6:30 pm
Current time: 18:30
Current time: evening.
Current time: evening (for many it is dinner time, but many eat dinner later).
-----------------------------------------------------------------------------
Foo: 6:30 pm
Foo: 18:30.
Foo: evening.
Foo: evening (for many it is dinner time, but many eat dinner later)
-----------------------------------------------------------------------------
Bar: 6:30 pm.
Bar: 18:30.
Bar: evening
Bar: evening (for many it is dinner time, but many eat dinner later).
-----------------------------------------------------------------------------
Baz: 6:30 pm
Baz: 18:30.
Baz: evening
Baz: evening (for many it is dinner time, but many eat dinner later)