fork download
  1. #include <string>
  2. #include <iostream>
  3. #include <type_traits>
  4.  
  5. // Forward declaration for our "default values" class.
  6. class CQQC;
  7.  
  8. namespace detail {
  9. // String wrapper, convertible to std::string.
  10. class literal_string {
  11. const char* const str;
  12. size_t sz; // Currently not needed, but useful if additional functionality is desired.
  13.  
  14. static constexpr size_t length(const char* const str_) {
  15. return *str_ ? 1 + length(str_ + 1) : 0;
  16. }
  17.  
  18. public:
  19. template<size_t N>
  20. constexpr literal_string(const char (&str_)[N])
  21. : str(str_), sz(N - 1) { }
  22.  
  23. constexpr literal_string(const char* const str_)
  24. : str(str_), sz(length(str_)) { }
  25.  
  26. operator std::string() const {
  27. return std::string(str);
  28. }
  29. };
  30.  
  31. // Generic "default values" type, specialise for each class.
  32. template<typename>
  33. struct Defaults_;
  34.  
  35. // Defaults for CQQC.
  36. template<>
  37. struct Defaults_<::CQQC> {
  38. int i, j, k;
  39. literal_string str;
  40.  
  41. /*
  42.   template<size_t N = 12>
  43.   constexpr Defaults_(int i_ = 0,
  44.   int j_ = 42,
  45.   int k_ = 359,
  46.   const char (&str_)[N] = "Hey, y'all!")
  47.   : i(i_), j(j_), k(k_), str(str_) { }
  48. */
  49.  
  50. constexpr Defaults_(int i_ = 0,
  51. int j_ = 42,
  52. int k_ = 359,
  53. const char* const str_ = "Hey, y'all!")
  54. : i(i_), j(j_), k(k_), str(str_) { }
  55. };
  56. } // namespace detail
  57.  
  58. // Boilerplate macro.
  59. #define MAKE_DEFAULTS(Class) \
  60.   constexpr static ::detail::Defaults_<Class> Defaults = ::detail::Defaults_<Class>()
  61.  
  62. class CQQC {
  63. static_assert(std::is_literal_type<detail::Defaults_<CQQC>>::value,
  64. "Default value holder isn't a literal type.");
  65.  
  66. MAKE_DEFAULTS(CQQC);
  67. // Expands to:
  68. // constexpr static ::detail::Defaults_<CQQC> Defaults = ::detail::Defaults_<CQQC>();
  69.  
  70. int i, j, k;
  71. std::string str;
  72.  
  73. public:
  74. // Allows the user to specify that they want the default value.
  75. enum Flags { DEFAULT };
  76.  
  77. // Initialise to defaults, unless otherwise specified.
  78. CQQC(int i_ = Defaults.i,
  79. int j_ = Defaults.j,
  80. int k_ = Defaults.k,
  81. std::string str_ = Defaults.str)
  82. : i(i_), j(j_), k(k_), str(str_) {}
  83.  
  84. bool isDefault() {
  85. return (i == Defaults.i &&
  86. j == Defaults.j &&
  87. k == Defaults.k &&
  88. str == Defaults.str.operator std::string());
  89. }
  90.  
  91. void set_i(int i_) { i = i_; }
  92.  
  93. // Set to default.
  94. void set_i(Flags f_) {
  95. if (f_ == Flags::DEFAULT) { i = Defaults.i; }
  96. }
  97.  
  98. // And so on...
  99. };
  100. constexpr detail::Defaults_<CQQC> CQQC::Defaults;
  101.  
  102. int main() {
  103. CQQC c1(4);
  104. CQQC c2;
  105.  
  106. if (c1.isDefault()) {
  107. std::cout << "c1 has default values.\n";
  108. } else {
  109. std::cout << "c1 is weird.\n";
  110. }
  111.  
  112. if (c2.isDefault()) {
  113. std::cout << "c2 has default values.\n";
  114. } else {
  115. std::cout << "c2 is weird.\n";
  116. }
  117.  
  118. c1.set_i(CQQC::DEFAULT);
  119. if (c1.isDefault()) {
  120. std::cout << "c1 now has default values.\n";
  121. } else {
  122. std::cout << "c1 is still weird.\n";
  123. }
  124. }
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
c1 is weird.
c2 has default values.
c1 now has default values.