fork(1) download
  1. #include <utility>
  2. #include <type_traits>
  3.  
  4. // SFINAE utility
  5. template<typename...> struct void_ { using type = void; };
  6. template<typename... T> using Void = typename void_<T...>::type;
  7.  
  8. /*
  9.  * In an ideal world std::result_of would just work instead of all that.
  10.  * Consider this as a write-once (until std::result_of is fixed), use-many
  11.  * situation.
  12.  */
  13. template<typename Sig, typename Sfinae = void> struct result_of {};
  14. template<typename F, typename... Args>
  15. struct result_of<
  16. F(Args...)
  17. , Void<decltype(std::declval<F>()(std::declval<Args>()...))>
  18. > {
  19. using type = decltype(std::declval<F>()(std::declval<Args>()...));
  20. };
  21. template<typename Sig> using ResultOf = typename result_of<Sig>::type;
  22.  
  23. /*
  24.  * Note how both template parameters have kind *, MonadicValue would be
  25.  * m a, not m. We don't whether MonadicValue is a specialization of some M<T>
  26.  * or not (or derived from a specialization of some M<T>). Note that it is
  27.  * possible to retrieve the a in M a via typename MonadicValue::value_type
  28.  * if MonadicValue is indeed a model of the proper concept.
  29.  *
  30.  * Defer actual implementation to the operator() of MonadicValue,
  31.  * which will do the monad-specific operation
  32.  */
  33. template<
  34. typename MonadicValue
  35. , typename F
  36. /* It is possible to put a self-documenting assertion here
  37.   that will *not* SFINAE out but truly result in a hard error
  38.   unless some conditions are not satisfied -- I leave this out
  39.   for brevity
  40.   , Requires<
  41.   MonadicValueConcept<MonadicValue>
  42.   // The two following constraints ensure that
  43.   // F has signature a -> m b
  44.   , Callable<F, ValueType<MonadicValue>>
  45.   , MonadicValueConcept<ResultOf<F(ValueType<MonadicValue>)>>
  46.   >...
  47.   */
  48. >
  49. ResultOf<MonadicValue(F)>
  50. bind(MonadicValue&& value, F&& f)
  51. { return std::forward<MonadicValue>(value)(std::forward<F>(f)); }
  52.  
  53. // Picking Maybe as an example monad because it's easy
  54. template<typename T>
  55. struct just_type {
  56. using value_type = T;
  57.  
  58. // Encapsulation omitted for brevity
  59. value_type value;
  60.  
  61. template<typename F>
  62. // The use of ResultOf means that we have a soft contraint
  63. // here, but the commented Requires clause in bind happens
  64. // before we would end up here
  65. ResultOf<F(value_type)>
  66. operator()(F&& f)
  67. { return std::forward<F>(f)(value); }
  68. };
  69.  
  70. template<typename T>
  71. just_type<T> just(T&& t)
  72. { return { std::forward<T>(t) }; }
  73.  
  74. template<typename T>
  75. just_type<typename std::decay<T>::type> make_just(T&& t)
  76. { return { std::forward<T>(t) }; }
  77.  
  78. struct nothing_type {
  79. // Note that because nothing_type and just_type<T>
  80. // are part of the same concept we *must* put in
  81. // a value_type member type -- whether you need
  82. // a value member or not however is a design
  83. // consideration with trade-offs
  84. struct universal { template<typename T> operator T(); };
  85. using value_type = universal;
  86.  
  87. template<typename F>
  88. nothing_type operator()(F const&) const
  89. { return {}; }
  90. };
  91. constexpr nothing_type nothing;
  92.  
  93. #include <cassert>
  94.  
  95. int main()
  96. {
  97. auto maybe = make_just(4);
  98. auto f = [](int i) { return just("Hello, World!"[i]); };
  99. auto&& r0 = bind(maybe, f);
  100. auto&& r1 = bind(bind(make_just(6), [](int i) { return just(i - 2); }), f);
  101. assert( &r0.value == &r1.value );
  102. auto r2 = bind(nothing, f);
  103. auto r3 = bind(maybe, [](int) { return nothing; });
  104. static_assert( std::is_same<decltype(r2), nothing_type>::value, "" );
  105. static_assert( std::is_same<decltype(r3), nothing_type>::value, "" );
  106. }
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:5:44: error: expected nested-name-specifier before 'type'
prog.cpp:5:44: error: using-declaration for non-member at class scope
prog.cpp:5:49: error: expected ';' before '=' token
prog.cpp:5:49: error: expected unqualified-id before '=' token
prog.cpp:6:25: error: expected unqualified-id before 'using'
prog.cpp:17:7: error: 'Void' was not declared in this scope
prog.cpp:17:64: error: template argument 2 is invalid
prog.cpp:18:1: error: expected unqualified-id before '>' token
prog.cpp:21:24: error: expected unqualified-id before 'using'
prog.cpp:49:1: error: 'ResultOf' does not name a type
prog.cpp:54:1: error: expected unqualified-id before 'template'
prog.cpp:71:1: error: 'just_type' does not name a type
prog.cpp:74:1: error: expected unqualified-id before 'template'
prog.cpp:85:11: error: expected nested-name-specifier before 'value_type'
prog.cpp:85:11: error: using-declaration for non-member at class scope
prog.cpp:85:22: error: expected ';' before '=' token
prog.cpp:85:22: error: expected unqualified-id before '=' token
prog.cpp:91:24: error: missing initializer for constexpr 'nothing'
prog.cpp: In function 'int main()':
prog.cpp:97:29: error: 'make_just' was not declared in this scope
prog.cpp:97:29: error: unable to deduce 'auto' from '<expression error>'
prog.cpp: In lambda function:
prog.cpp:98:56: error: 'just' was not declared in this scope
prog.cpp:98:59: error: return-statement with a value, in function returning 'void'
prog.cpp: In function 'int main()':
prog.cpp:99:30: error: 'bind' was not declared in this scope
prog.cpp:99:30: error: unable to deduce 'auto&&' from '<expression error>'
prog.cpp: In lambda function:
prog.cpp:100:70: error: 'just' was not declared in this scope
prog.cpp:100:73: error: return-statement with a value, in function returning 'void'
prog.cpp: In function 'int main()':
prog.cpp:100:78: error: unable to deduce 'auto&&' from '<expression error>'
prog.cpp:102:30: error: unable to deduce 'auto' from '<expression error>'
prog.cpp:103:54: error: unable to deduce 'auto' from '<expression error>'
prog.cpp:104:59: error: template argument 1 is invalid
prog.cpp:105:59: error: template argument 1 is invalid
stdout
Standard output is empty