fork(1) download
  1. #include <iostream>
  2. #include <type_traits>
  3. #include <functional>
  4. #include <cstdint>
  5. #include <typeinfo>
  6. #include <string>
  7.  
  8. // Just gonna do this for the sake of our example here.
  9. using FilePath = std::string;
  10.  
  11. // Parameter match checking.
  12. namespace ParameterCheck {
  13. template<typename T, typename... Ts> struct parameter_match : public std::false_type {};
  14.  
  15. // Declare (GetColor, int16_t*) valid.
  16. template<> struct parameter_match<int (*)(int16_t*), int16_t*> : public std::true_type {};
  17.  
  18. // Declare (GetFile, FilePath&) valid.
  19. // template<> struct parameter_match<int (*)(FilePath&), FilePath&> : public std::true_type {}; // You'd think this would work, but...
  20. template<> struct parameter_match<int (*)(FilePath&), FilePath> : public std::true_type {}; // Nope!
  21. // For some reason, reference-ness isn't part of the templated type. It acts as if it was "template<typename T> void func(T& arg)" instead.
  22.  
  23. // Declare (WriteDocument, const FilePath&, const char*, bool) valid.
  24. // template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), const FilePath, const char*, bool> : public std::true_type {};
  25. // template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), const FilePath&, const char*, bool> : public std::true_type {};
  26. template<> struct parameter_match<int (*)(const FilePath&, const char*, bool), FilePath, const char*, bool> : public std::true_type {};
  27. // More reference-as-template-parameter wonkiness: Out of these three, only the last works.
  28.  
  29. // Declare everything without a parameter list valid.
  30. template<typename T> struct parameter_match<T (*)()> : public std::true_type { };
  31. } // namespace ParameterCheck
  32.  
  33. // Discount return type deduction:
  34. namespace ReturnTypeCapture {
  35. // Credit goes to Angew ( http://stackoverflow.com/a/18695701/5386374 )
  36. template<typename T> struct ret_type;
  37.  
  38. template<typename RT, typename... Ts> struct ret_type<RT (*)(Ts...)> {
  39. using type = RT;
  40. };
  41. } // namespace ReturnTypeCapture
  42.  
  43. // Alias declarations:
  44. template<typename F, typename... Ts> using PChecker = ParameterCheck::parameter_match<F, Ts...>;
  45. template <typename F> using RChecker = typename ReturnTypeCapture::ret_type<F>::type;
  46.  
  47.  
  48. // ---------------
  49.  
  50. // Quick implementations of your example functions.
  51.  
  52. int GetColor(int16_t* color) {
  53. std::cout << "GetColor(int16_t*) with parameter: " << *color << std::endl;
  54. return 3;
  55. }
  56.  
  57. int GetFile(FilePath& file) {
  58. std::cout << "GetFile(FilePath&)." << std::endl;
  59. std::cout << "..." << file << "? Get it yourself!" << std::endl;
  60. return -6;
  61. }
  62.  
  63. int WriteDocument(const FilePath& file, const char* fileFormatName, bool askForParams) {
  64. std::cout << "WriteDocument(const FilePath&, const char*, bool) with: "
  65. << file << ", " << fileFormatName << ", and " << std::boolalpha
  66. << askForParams << "." << std::noboolalpha << std::endl;
  67. std::cout << "Eh, I'll write it tomorrow." << std::endl;
  68. return 8;
  69. }
  70.  
  71. // ---------------
  72.  
  73. // The actual calling function, C++11 style.
  74. template<typename Func, typename... Ts> auto caller2(std::true_type x, Func f, Ts... args) -> RChecker<Func> {
  75. std::cout << "Now calling... ";
  76. return f(args...);
  77. }
  78.  
  79. // Parameter mismatch overload.
  80. template<typename Func, typename... Ts> auto caller2(std::false_type x, Func f, Ts... args) -> RChecker<Func> {
  81. std::cout << "Parameter list mismatch." << std::endl;
  82. return static_cast<RChecker<Func> >(0); // Just to make sure we don't break stuff.
  83. }
  84.  
  85. // Wrapper to check for parameter mismatch, C++14 style.
  86. template<typename Func, typename... Ts> auto caller(Func f, Ts... args) /* -> RChecker<Func> */ {
  87. // return caller2(ParameterCheck::parameter_match<Func, Ts...>{}, f, args...);
  88. return caller2(PChecker<Func, Ts...>{}, f, args...);
  89. }
  90.  
  91. // ---------------
  92.  
  93. // To show what std::true_type and std::false_type act as.
  94.  
  95. template<bool N> void fnarg2(std::integral_constant<bool, N> x) {
  96. std::cout << "Integral constant<bool, N> value: " << x.value << std::endl;
  97. }
  98.  
  99. template<typename F, typename... Ts> void fnarg(F f, Ts... ts) {
  100. fnarg2(ParameterCheck::parameter_match<F, Ts...>{});
  101. }
  102.  
  103. // ---------------
  104.  
  105. // Something I used to get things working, I left it here to show something odd:
  106.  
  107. // Which one is true and which is false flips depending on whether the parameter is T or T&.
  108. template<typename T> void sameness(T& t) {
  109. std::cout << std::boolalpha;
  110. std::cout << "cfp is const: " << std::is_same<T, const FilePath>::value << std::endl;
  111. std::cout << "cfp ain't const: " << std::is_same<T, FilePath>::value << std::endl;
  112. std::cout << std::noboolalpha;
  113. }
  114.  
  115. // ---------------
  116.  
  117. // Return type sorcery:
  118.  
  119. std::string f1() { return std::string("Nyahaha."); }
  120.  
  121. int f2() { return -42; }
  122.  
  123. char f3() { return '&'; }
  124.  
  125. // template<typename R, typename F> auto rtCaller2(R r, F f) -> typename R::type {
  126. // template<typename F> auto rtCaller2(F f) -> typename ReturnTypeCapture::ret_type<F>::type {
  127. template<typename F> auto rtCaller2(F f) -> RChecker<F> {
  128. return f();
  129. }
  130.  
  131. template<typename F> void rtCaller(F f) {
  132. // auto a = rtCaller2(ReturnTypeCapture::ret_type<F>{}, f);
  133. auto a = rtCaller2(f);
  134. std::cout << a << " (type: " << typeid(a).name() << ")" << std::endl;
  135. }
  136.  
  137. // ---------------
  138.  
  139. int main() {
  140. int16_t i = 3333;
  141. FilePath fp = "C:\\Windows\\win.ini";
  142. const FilePath cfp = (const FilePath) fp; // In case you didn't know, it's a const FilePath. ^_^
  143. const char* cc = "Fred Format\n";
  144. bool b = true;
  145.  
  146. // Checking int(*)(int16_t*):
  147. auto gc = caller(GetColor, &i); // Valid call.
  148. caller(GetColor, &i, i); // Invalid call.
  149. std::cout << std::endl;
  150.  
  151. // Checking int(*)(FilePath&):
  152. auto gf = caller(GetFile, fp); // Valid call.
  153. caller(GetFile, main); // Invalid call.
  154. std::cout << std::endl;
  155.  
  156. //Checking int(*)(const FilePath&, const char*, bool):
  157. auto wd = caller(WriteDocument, cfp, cc, b); // Valid call.
  158. caller(WriteDocument, cfp, const_cast<char*>(cc), b); // Invalid call.
  159. std::cout << std::endl;
  160.  
  161. auto f_1 = caller(f1);
  162. auto f_2 = caller(f2);
  163. auto f_3 = caller(f3);
  164. std::cout << std::endl;
  165.  
  166. std::cout << "Return values: " << gc << ", " << gf << ", " << wd << ", "
  167. << f_1 << ", " << f_2 << ", and " << f_3 << std::endl;
  168.  
  169. // std::cout << std::endl;
  170. // sameness(cfp);
  171.  
  172. // Three std::true_types, and one std::false_type.
  173. std::cout << std::boolalpha << std::endl;
  174. fnarg(GetColor, &i);
  175. fnarg(GetFile, fp);
  176. fnarg(WriteDocument, cfp, cc, b);
  177. fnarg(i);
  178. std::cout << std::noboolalpha << std::endl;
  179.  
  180. // Return type stuff:
  181. std::cout << "Behold, return type sorcery!" << std::endl;
  182. rtCaller(f1);
  183. rtCaller(f2);
  184. rtCaller(f3);
  185.  
  186. }
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
Now calling... GetColor(int16_t*) with parameter: 3333
Parameter list mismatch.

Now calling... GetFile(FilePath&).
...C:\Windows\win.ini?  Get it yourself!
Parameter list mismatch.

Now calling... WriteDocument(const FilePath&, const char*, bool) with: C:\Windows\win.ini, Fred Format
, and true.
Eh, I'll write it tomorrow.
Parameter list mismatch.

Now calling... Now calling... Now calling... 
Return values: 3, -6, 8, Nyahaha., -42, and &

Integral constant<bool, N> value: true
Integral constant<bool, N> value: true
Integral constant<bool, N> value: true
Integral constant<bool, N> value: false

Behold, return type sorcery!
Nyahaha. (type: Ss)
-42 (type: i)
& (type: c)