fork download
  1. // BEGIN TYPE_CHECK.H
  2. // https://w...content-available-to-author-only...x.com/s/dkft2pcur5y76aq/type_check.h
  3. #ifndef TYPE_CHECK_H
  4. #define TYPE_CHECK_H
  5.  
  6.  
  7. //------------------------------------------------------------------------------
  8. // TYPE_CHECK()
  9.  
  10. /** Type Check.
  11.   * Test type `T_` for the presence or absence of type `T_::TYPE_`.
  12.   * This Provides a convenient frontend for a SFINAE (substitution failure is
  13.   * not an error) idiom.
  14.   *
  15.   * Defines a `struct NAME_` which is instantiated with `HAS_TYPE_` as its body
  16.   * for types `T_` when `T_::TYPE_` exists, and with `NO_TYPE_` as its body for
  17.   * types `T_` which don't have a `T_::TYPE_`. `HAS_TYPE_` and `NO_TYPE_` can
  18.   * contain multiple declarations, which should be seperated by `;` (as in a
  19.   * normal `struct` body).
  20.   *
  21.   * A trailing `;` is provided for the last declaration by the macro, so this can
  22.   * be omitted at the point of use. Unless the flag TYPE_CHECK_NO_VA_ARGS is
  23.   * #defined, then `HAS_TYPE_` and `NO_TYPE_` can be parenthesized if necessary
  24.   * (if they contain unparenthesized commas, for example).
  25.   * \sa TYPE_CHECK_FRIEND()
  26.   */
  27. #define TYPE_CHECK(NAME_, T_, TYPE_, HAS_TYPE_, NO_TYPE_) \
  28.   template<typename T_, typename = void>struct NAME_ { \
  29.   tc_STRIP_PARENS(NO_TYPE_); \
  30.   }; \
  31.   template<typename T_> \
  32.   struct NAME_<T_, \
  33.   typename ::tc_::HasType<typename T_::TYPE_>::Type> { \
  34.   tc_STRIP_PARENS(HAS_TYPE_); \
  35.   }
  36.  
  37.  
  38. //------------------------------------------------------------------------------
  39. // TYPE_CHECK_FRIEND()
  40.  
  41. /** Type Check Friend.
  42.   * This macro can be placed in a type declaration, to indicate that the body of
  43.   * the check defined as `NAME_` can acces this type's protected/private members.
  44.   * \sa TYPE_CHECK()
  45.   */
  46. #define TYPE_CHECK_FRIEND(NAME_) \
  47.   template<typename, typename>friend struct NAME_;
  48.  
  49.  
  50. //------------------------------------------------------------------------------
  51. // Internal details follow...
  52.  
  53. #ifndef TYPE_CHECK_NO_VA_ARGS
  54.  
  55. // Detect and strip parentheses from __VA_ARGS__.
  56. #define tc_STRIP_PARENS(...) \
  57.   tc_IF( tc_HAS_PARENS(__VA_ARGS__), \
  58.   tc_PASSTHROUGH(tc_PASSTHROUGH __VA_ARGS__), \
  59.   tc_PASSTHROUGH(__VA_ARGS__) )
  60.  
  61. #define tc_IF(COND_, TRUE_, FALSE_) \
  62.   tc_JOIN2(tc_DO_IF_, tc_NEQ(COND_, 0)) \
  63.   (tc_PASSTHROUGH(TRUE_), tc_PASSTHROUGH(FALSE_))
  64. #define tc_DO_IF_0(T_, F_) F_
  65. #define tc_DO_IF_1(T_, F_) T_
  66.  
  67. #define tc_HAS_PARENS(...) \
  68.   tc_NEQ( tc_COMMA_COUNT(__VA_ARGS__), \
  69.   tc_COMMA_COUNT(tc_COMMA_IF_PARENS __VA_ARGS__) )
  70.  
  71. #define tc_NEQ(A_, B_) tc_DO_NEQ(A_, B_)
  72. #define tc_DO_NEQ(A_, B_) tc_DO_NEQ_##A_##B_
  73. #define tc_DO_NEQ_00 0
  74. #define tc_DO_NEQ_01 1
  75. #define tc_DO_NEQ_10 1
  76. #define tc_DO_NEQ_11 0
  77.  
  78. #define tc_JOIN2(A_, B_) tc_DO_JOIN2(A_, B_)
  79. #define tc_DO_JOIN2(A_, B_) A_##B_
  80.  
  81. #define tc_PASSTHROUGH(...) __VA_ARGS__
  82. #define tc_COMMA_IF_PARENS(...) ,
  83.  
  84. // counts commas in (...)
  85. #define tc_COMMA_COUNT(...) tc_LAST_ARG(__VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
  86. #define tc_LAST_ARG(a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, o_, p_, q_, r_, s_, t_, u_, v_, w_, x_, y_, z_, ...) z_
  87.  
  88. #else//TYPE_CHECK_NO_VA_ARGS
  89.  
  90. // Default case for compilers with no __VA_ARGS__ support
  91. #define tc_STRIP_PARENS(X_) X_
  92.  
  93. #endif//TYPE_CHECK_NO_VA_ARGS
  94.  
  95. //------------------------------------------------------------------------------
  96. //
  97. namespace tc_ {
  98. template<typename T> struct HasType { typedef void Type; };
  99. } // namespace type_check_
  100.  
  101.  
  102. #endif//TYPE_CHECK_H
  103. // END TYPE_CHECK.H
  104.  
  105. // BEGIN MAIN.CPP
  106. // https://w...content-available-to-author-only...x.com/s/5mg4190ao3o9tgd/main.cpp
  107. //#include "type_check.h" // it's right above this!
  108.  
  109. #include <stdio.h>
  110. #include <stdlib.h>
  111.  
  112.  
  113. const char *strbool(bool b) { return b ? "true" : "false"; }
  114.  
  115. // testing structs
  116. struct TestingF {}; // No TestingF::TypeToCheck exists
  117. struct TestingT { typedef void TypeToCheck; };
  118.  
  119.  
  120. //------------------------------------------------------------------------------
  121. // Test 1
  122. // Simple true/false check.
  123.  
  124. TYPE_CHECK(Test1Check, T, TypeToCheck,
  125. static const bool VALUE = true, // Test1Check body when T::TypeToCheck exists
  126. static const bool VALUE = false); //Test1Check body default
  127.  
  128. bool test1() {
  129.  
  130. bool f = Test1Check<TestingF>::VALUE; // -> false
  131. bool t = Test1Check<TestingT>::VALUE; // -> true
  132.  
  133. printf("t = %s, f = %s\n", strbool(t), strbool(f));
  134.  
  135. return !f && t;
  136. }
  137.  
  138.  
  139. #ifndef TYPE_CHECK_NO_VA_ARGS
  140. //------------------------------------------------------------------------------
  141. // Test 2
  142. // Parens around the 'body' clauses to handle the commas in the int declarations.
  143.  
  144. TYPE_CHECK( Test2Check, T, TypeToCheck,
  145. (static const int a = 10, b = 20, c = 30),
  146. (static const int a = 3, b = 4, c = 5) );
  147.  
  148. bool test2() {
  149.  
  150. typedef Test2Check<TestingF> T2F;
  151. typedef Test2Check<TestingT> T2T;
  152.  
  153. int sum_f = T2F::a + T2F::b + T2F::c;
  154. int sum_t = T2T::a + T2T::b + T2T::c;
  155.  
  156. printf("sum_f = %u, sum_t = %u\n", sum_f, sum_t);
  157.  
  158. return (12 == sum_f) && (60 == sum_t);
  159. }
  160. #endif//TYPE_CHECK_NO_VA_ARGS
  161.  
  162.  
  163. //------------------------------------------------------------------------------
  164. // Test 3
  165. // Select functions.
  166.  
  167. TYPE_CHECK( Test3Check, T, TypeToCheck,
  168. static int test(int &a) { return ++a; }, // trailing comma needed here!
  169. static int test(int &a) { return --a; } );
  170.  
  171. bool test3() {
  172.  
  173. int q =10;
  174. typedef Test3Check<TestingF> T3F;
  175. typedef Test3Check<TestingT> T3T;
  176.  
  177. int u = T3F::test(q);
  178. int v = T3F::test(q);
  179. int w = T3F::test(q);
  180. int x = T3T::test(q);
  181. int y = T3T::test(q);
  182. int z = T3T::test(q);
  183.  
  184. printf("%u, %u, %u, %u, %u, %u\n", u, v, w, x, y, z);
  185.  
  186. return
  187. (9 == u) && (8 == v) && (7 == w) &&
  188. (8 == x) && (9 == y) && (10 == z) &&
  189. true;
  190. }
  191.  
  192.  
  193. //------------------------------------------------------------------------------
  194. // Test 4
  195. // private implementations and TYPE_CHECK_FRIEND()
  196.  
  197. class Test4ExampleF {};
  198. class Test4ExampleT {
  199. typedef int TypeToCheck;
  200. TYPE_CHECK_FRIEND(Test4Check); // Give Test4Check access to internals
  201. };
  202.  
  203. TYPE_CHECK(Test4Check, T, TypeToCheck,
  204. static const bool VALUE = true, // Test4Check body when T::TypeToCheck exists
  205. static const bool VALUE = false); //Test4Check body default
  206.  
  207. bool test4() {
  208.  
  209. bool f = Test4Check<Test4ExampleF>::VALUE; // -> false
  210. bool t = Test4Check<Test4ExampleT>::VALUE; // -> true
  211.  
  212. printf("t = %s, f = %s\n", strbool(t), strbool(f));
  213.  
  214. return !f && t;
  215. }
  216.  
  217.  
  218. //------------------------------------------------------------------------------
  219. // Test 5
  220. // Something a bit more like 'real-world' usage.
  221.  
  222. // Use the HAS_SPECIAL_METHOD() macro in a type declaration to arrange for
  223. // Test5Check<X>::result() to call the named method...
  224. #define HAS_SPECIAL_METHOD(NAME_) \
  225.   typedef void HasSpecialMethod; /* the tag */\
  226.   int do_special_() { return NAME_(); } /* indirect call to NAME_() */
  227.  
  228. struct Test5Default {
  229. Test5Default(int d): data(d) {}
  230. int data;
  231. };
  232.  
  233. struct Test5Special1 {
  234. Test5Special1(int d): data(d) {}
  235. int data;
  236.  
  237. int special1() { return data * 4; }
  238. HAS_SPECIAL_METHOD(special1);
  239. };
  240.  
  241. struct Test5Special2 {
  242. Test5Special2(int d): data(d) {}
  243. int data;
  244.  
  245. int special2() { return data - 100; }
  246. HAS_SPECIAL_METHOD(special2);
  247. };
  248.  
  249. // use X instead of T for fun...
  250. TYPE_CHECK(Test5Check, X, HasSpecialMethod,
  251.  
  252. static int result(X &x) {
  253. return x.do_special_();
  254. },
  255.  
  256. static int result(X &x) { return x.data; } );
  257.  
  258. template<typename X>
  259. int test5result(X &x) { return Test5Check<X>::result(x); }
  260.  
  261. bool test5() {
  262. Test5Default def(100);
  263. Test5Special1 sp1(100);
  264. Test5Special2 sp2(100);
  265.  
  266. printf("%d, %d, %d\n",
  267. test5result(def),
  268. test5result(sp1),
  269. test5result(sp2));
  270.  
  271. return
  272. 100 == test5result(def) &&
  273. 400 == test5result(sp1) &&
  274. 0 == test5result(sp2) &&
  275. true;
  276. }
  277.  
  278.  
  279. //------------------------------------------------------------------------------
  280. int main() {
  281.  
  282. bool ok =
  283. test1() &&
  284. #ifndef TYPE_CHECK_NO_VA_ARGS
  285. test2() &&
  286. #endif//TYPE_CHECK_NO_VA_ARGS
  287. test3() &&
  288. test4() &&
  289. test5() &&
  290. true;
  291.  
  292. printf("\nAll tests passed: %s\n", strbool(ok));
  293.  
  294. return ok ? EXIT_SUCCESS : EXIT_FAILURE;
  295. }
  296.  
  297.  
  298. // END MAIN.CPP
  299.  
  300.  
Success #stdin #stdout 0s 2684KB
stdin
Standard input is empty
stdout
t = true, f = false
sum_f = 12, sum_t = 60
9, 8, 7, 8, 9, 10
t = true, f = false
100, 400, 0

All tests passed: true