fork download
  1. ///////////////////////////////////////////////
  2. // reference implementation for swallowing
  3. // return values in a 'function<void(...)>'
  4. // and thus accept a wider range of callables
  5. //
  6. // most of this is boiler-plate code to mimic
  7. // the implementation in libc++ w.r.t. the
  8. // SFINAE trickery
  9. //
  10. // note that 'invoke_test' is actually
  11. // implemented to facilitate reuse by
  12. // 'maybe_swallow', keeping it DRY.
  13. //
  14. // -- Xeo
  15. ///////////////////////////////////////////////
  16.  
  17. #include <type_traits>
  18. #include <utility>
  19. #include <iostream>
  20.  
  21. // naive implementations
  22. struct not_a_type{};
  23.  
  24. auto invoke_test(...)
  25. -> not_a_type;
  26.  
  27. // only functor and function pointer support for reference
  28. template<class F, class... As>
  29. auto invoke_test(F&& f, As&&... as)
  30. -> decltype(std::forward<F>(f)(std::forward<As>(as)...))
  31. { // actually implemented for maybe_swallow
  32. return std::forward<F>(f)(std::forward<As>(as)...);
  33. };
  34.  
  35. template<class F, class... As>
  36. struct invokable{
  37. typedef decltype(
  38. invoke_test(std::declval<F>(), std::declval<As>()...)
  39. ) type;
  40. static bool const value =
  41. !std::is_same<type, not_a_type>::value;
  42. };
  43.  
  44. template<class F, class... As>
  45. struct invoke_of{
  46. typedef typename invokable<F, As...>::type type;
  47. };
  48.  
  49. template<class R1, class R2>
  50. struct convertible_check
  51. : std::is_convertible<R1, R2> {};
  52.  
  53. template<class R1>
  54. struct convertible_check<R1, void>{
  55. static bool const value = true;
  56. };
  57.  
  58. // workaround for missing partial function specialization
  59. template<class T> struct type{};
  60.  
  61. template<class R, class F, class... As>
  62. auto maybe_swallow(type<R>, F&& f, As&&... as)
  63. -> typename invoke_of<F, As...>::type
  64. {
  65. return invoke_test(std::forward<F>(f), std::forward<As>(as)...);
  66. }
  67.  
  68. template<class F, class... As>
  69. void maybe_swallow(type<void>, F&& f, As&&... as)
  70. {
  71. (void)invoke_test(std::forward<F>(f), std::forward<As>(as)...);
  72. }
  73.  
  74. template<class Sig>
  75. class function;
  76.  
  77. // lazy me supports only function pointer
  78. template<class R, class... As>
  79. class function<R(As...)>
  80. {
  81. template<class> struct dump;
  82.  
  83. template<class F, bool = invokable<F&, As...>::value>
  84. struct callable;
  85.  
  86. template<class F>
  87. struct callable<F, true>{
  88. static bool const value =
  89. convertible_check<typename invoke_of<F&, As...>::type, R>::value;
  90. };
  91. template<class F>
  92. struct callable<F, false>{ static bool const value = false; };
  93.  
  94. template<class F>
  95. struct enable_if_callable
  96. : std::enable_if<callable<F>::value> {};
  97.  
  98. public:
  99. template<class Fptr>
  100. function(Fptr f, typename enable_if_callable<Fptr>::type* = 0);
  101.  
  102. template<class... FAs>
  103. R operator()(FAs&&... fas){
  104. return _f(_f_holder, std::forward<FAs>(fas)...);
  105. }
  106.  
  107. private:
  108. typedef void (*void_fptr)();
  109. typedef R (*call_func)(void_fptr, As...);
  110. call_func _f;
  111. void_fptr _f_holder;
  112.  
  113. template<class Fptr>
  114. static R call_fptr(void_fptr fh, As... as){
  115. //dump<Fptr>();
  116. return maybe_swallow(type<R>(), (Fptr)fh, as...);
  117. }
  118. };
  119.  
  120. template<class R, class... As>
  121. template<class Fptr>
  122. function<R(As...)>::function(Fptr f,
  123. typename enable_if_callable<Fptr>::type*)
  124. : _f(&call_fptr<Fptr>)
  125. , _f_holder((void_fptr)f)
  126. {
  127. }
  128.  
  129. int foo(int i){ std::cout << i << "\n"; return i; }
  130. void bar(int i){ (void)foo(i); }
  131.  
  132. void baz(function<void(int)> f){ f(42); }
  133. void baz(function<void(int,int)>){}
  134.  
  135. void quux(function<void(int)>){}
  136. void quux(function<int(int)>){}
  137.  
  138. int main(){
  139. function<void(int)> f1(foo), f2(bar);
  140. f1(42);
  141. f2(42);
  142. baz(foo);
  143. baz(bar);
  144.  
  145. //quux(foo);
  146. // comment in for ambiguous overload error
  147. // since function<void(...)> now accepts any
  148. // callable as long as the parameters work
  149.  
  150. // could be "explained" that it fits with the
  151. // rule that one can't overload on return type
  152. // alone. :)
  153. }
Success #stdin #stdout 0s 2828KB
stdin
Standard input is empty
stdout
42
42
42
42