fork download
  1.  
  2. template<class _Ty>
  3. struct buildpath;
  4.  
  5. template<int N, class _Path, char ...chars>
  6. struct build_path;
  7.  
  8.  
  9. //-----------------------------------------------------------------------------
  10. // constexpr for strlen
  11. template<char ..._chars>
  12. struct constexpr_strlen
  13. {
  14. static constexpr const int value = sizeof...(_chars);
  15. };
  16.  
  17. //-----------------------------------------------------------------------------
  18. // constexpr string
  19. // holds a reference to a string and its size and length as a constexpr
  20. template<const char *_Str, int _Sz>
  21. struct constexpr_string
  22. {
  23. static constexpr const int size = _Sz;
  24. static constexpr const int length = _Sz - 1;
  25. static constexpr const char *str = _Str;
  26. };
  27.  
  28. //-----------------------------------------------------------------------------
  29. // a constexpr empty string
  30. struct constexpr_string_empty
  31. {
  32. static constexpr const char *str = "";
  33. static constexpr const int size = 1;
  34. static constexpr const int length = 0;
  35. };
  36.  
  37. //-----------------------------------------------------------------------------
  38. // exposes name and parent of this path element
  39. template<class _Ty, class _NameStr, class _ParPathTy>
  40. struct PathElemInfo : _NameStr
  41. {
  42. using parent = _ParPathTy;
  43. };
  44.  
  45. //-----------------------------------------------------------------------------
  46. // An empty path element info
  47. struct PathElemInfoEmpty : constexpr_string_empty
  48. {};
  49.  
  50. //-----------------------------------------------------------------------------
  51. // An empty path
  52. struct PathEmpty
  53. {
  54. using __info = PathElemInfoEmpty;
  55. };
  56.  
  57. //-----------------------------------------------------------------------------
  58. // Path is used to construct path element + parents which can then be
  59. // serialize to compile-time static strings.
  60. template<class _Ty, class _NameStr = constexpr_string_empty, class _ParPathTy = PathEmpty>
  61. struct Path
  62. {
  63. using __type = Path<_Ty, _NameStr, _ParPathTy>;
  64. using __info = PathElemInfo<_Ty, _NameStr, _ParPathTy>;
  65. static constexpr const char *path() { return buildpath<__type>::value(); }
  66. };
  67.  
  68. //=============================================================================
  69. // Construct constexpr strings from paths
  70.  
  71. //-----------------------------------------------------------------------------
  72. // Add a '.' between path elements
  73. template<int N, class _Path, char ...chars>
  74. struct build_path_dot
  75. {
  76. static constexpr const char *value() {
  77. return build_path<N, _Path, '.', chars...>::value();
  78. }
  79. };
  80.  
  81. //-----------------------------------------------------------------------------
  82. // Don't add a '.' on an empty path element (the root element is always empty)
  83. template<int N, char ...chars>
  84. struct build_path_dot<N, PathEmpty, chars...>
  85. {
  86. static constexpr const char *value() {
  87. return build_path<N, PathEmpty, chars...>::value();
  88. }
  89. };
  90.  
  91. //-----------------------------------------------------------------------------
  92. // Don't add a '.' at the beginning of the string
  93. template<char ...chars>
  94. struct build_path_dot<0, PathEmpty, chars...>
  95. {
  96. static constexpr const char *value() {
  97. return build_path<0, PathEmpty, chars...>::value;
  98. }
  99. };
  100.  
  101. //-----------------------------------------------------------------------------
  102. // Compiler gets confused if we don't provide this one as well...
  103. template<class _Path, char ...chars>
  104. struct build_path_dot<0, _Path, chars...>
  105. {
  106. static constexpr const char *value() {
  107. return build_path<0, _Path, chars...>::value();
  108. }
  109. };
  110.  
  111. //-----------------------------------------------------------------------------
  112. // Extract the Nth character from the current path element
  113. template<int N, class _Path, char ...chars>
  114. struct build_path
  115. {
  116. static constexpr const char *value() {
  117. return build_path<N - 1, _Path, _Path::__info::str[N - 1], chars...>::value();
  118. }
  119. };
  120.  
  121. //-----------------------------------------------------------------------------
  122. // When a path element is depleted, add a dot and move on to the next path element
  123. template<class _Path, char ...chars>
  124. struct build_path<0, _Path, chars...>
  125. {
  126. static constexpr const char *value() {
  127. return build_path_dot<_Path::__info::parent::__info::length, typename _Path::__info::parent, chars...>::value();
  128. }
  129. };
  130.  
  131. //-----------------------------------------------------------------------------
  132. // When the last path element is depleted, build the actual string from all
  133. // the characters we have extracted
  134. template<char ...chars>
  135. struct build_path<0, PathEmpty, chars...>
  136. {
  137. static constexpr const int size() {
  138. return constexpr_strlen<chars...>::value + 1;
  139. }
  140. static const char value[size()];
  141. };
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Allocate static storage for this path
  145. template<char ...chars>
  146. const char build_path<0, PathEmpty, chars...>::value[] = { chars..., 0 };
  147.  
  148.  
  149. //-----------------------------------------------------------------------------
  150. // shortcut to make usage easier
  151. template<class _Ty>
  152. struct buildpath {
  153. static constexpr const char *value() { return build_path<_Ty::__info::length, _Ty>::value(); }
  154. };
  155.  
  156. //=============================================================================
  157. // Sample usage
  158.  
  159. struct A;
  160. struct B;
  161. struct C;
  162.  
  163. template<class _NameStr, class _ParPathTy>
  164. struct Path<A, _NameStr, _ParPathTy>
  165. {
  166. using __type = Path<A, _NameStr, _ParPathTy>;
  167. using __info = PathElemInfo<A, _NameStr, _ParPathTy>;
  168.  
  169. static constexpr const char *path() { return buildpath<__type>::value(); }
  170.  
  171. static constexpr const char __b[] = "obj_b";
  172. using b = Path<B, constexpr_string<__type::__b, sizeof(__type::__b)>, __type>;
  173.  
  174. static constexpr const char __b2[] = "obj_b2";
  175. using b2 = Path<B, constexpr_string<__type::__b2, sizeof(__type::__b2)>, __type>;
  176. };
  177.  
  178. template<class _NameStr, class _ParPathTy>
  179. struct Path<B, _NameStr, _ParPathTy>
  180. {
  181. using __type = Path<B, _NameStr, _ParPathTy>;
  182. using __info = PathElemInfo<B, _NameStr, _ParPathTy>;
  183. static constexpr const char *path() { return buildpath<__type>::value(); }
  184.  
  185. static constexpr const char __c[] = "obj_c";
  186. using c = Path<C, constexpr_string<__type::__c, sizeof(__type::__c)>, __type>;
  187.  
  188. static constexpr const char __a[] = "obj_a";
  189. using a = Path<A, constexpr_string<__type::__a, sizeof(__type::__a)>, __type>;
  190. };
  191.  
  192.  
  193. #include <iostream>
  194. using namespace std;
  195. int main(int argc, const char *argv[])
  196. {
  197. using Q = Path<A>;
  198. cout << "root: " << Q::path() << endl;
  199. cout << "b: " << Q::b::path() << endl;
  200. cout << "b.c: " << Q::b::c::path() << endl;
  201.  
  202. // make sure we can have multiple identical types under the same path
  203. cout << "b2.c: " << Q::b2::c::path() << endl;
  204.  
  205. // make sure we can have recursive paths as well
  206. cout << "b2.a.b.a.b.c: " << Q::b2::a::b::a::b::c::path() << endl;
  207. }
  208.  
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
root: 
b: obj_b
b.c: obj_b.obj_c
b2.c: obj_b2.obj_c
b2.a.b.a.b.c: obj_b2.obj_a.obj_b.obj_a.obj_b.obj_c