Combining Literals with Expression Templates Based On CRTP - c++

This is the basic implementation I'm using for expression templates, based on the CRTP which allows me to conveniently combine multiple types of operations without also asking everything to be an expression tree.
template<typename E>
struct OpExpression
{
auto eval(iter_type n) const
{
return static_cast<E const&>(*this).eval(n);
}
};
template<typename T>
struct OpFrame : OpExpression<OpFrame<T>>
{
T *ptr;
OpFrame(T *ptr) : ptr{ ptr } {}
T eval(iter_type n) const
{
return ptr[n];
}
};
template<typename T>
struct OpLiteral : OpExpression<OpLiteral<T>>
{
T value;
OpLiteral<T>(T value) : value{ value } {}
T eval(iter_type) const
{
return value;
}
operator T() const
{
return value;
}
};
Here is a class to apply the addition between two values (and an operator overload to make it pretty):
template<typename E1, typename E2>
struct OpFrameAdd : OpExpression<OpFrameAdd<E1, E2>>
{
OpFrameAdd(E1 const a, E2 const b) : a{ a }, b{ b } {}
auto eval(iter_type n) const
{
return a.eval(n) + b.eval(n);
}
protected:
E1 const a;
E2 const b;
};
template<typename E1, typename E2>
auto operator+(OpExpression<E1> const& a, OpExpression<E2> const& b)
{
auto v = OpFrameAdd<E1, E2>(*static_cast<const E1*>(&a), *static_cast<const E2*>(&b));
return v;
}
To provide some more detail/context; I have an array holding a bunch of values (could be of various types), and an arithmetic expression defining how I want to transform that array into another one. However, this transformation is not concrete, so I'm using the expression tree as something I can pass to objects that will then handle it in different ways (i.e. I have to wait to evaluate it). Additionally, I only want to define the expression once.
I'm wondering, if based on this design, I can introduce literals (without casting to an OpLiteral) to my expressions? For example:
double arr[100]{ 0 };
OpFrame arr_t(arr);
// I can do this
auto ev1 = arr_t + arr_t + arr_t + OpLiteral(2.0);
// But I would prefer to do this
auto ev2 = arr_t + arr_t + arr_t + 2.0;
Based on my question here, I know 2.0 won't automatically cast to the correct type, but the solution is also not compatible with this design (it causes either an ambiguous call, or in bigger expressions, mixes up the tree by applying the generic template rather than one based on OpExpression<T>).
How I had tried to implement that solution:
template<typename E1, typename T>
auto operator+(OpExpression<E1> const& a, T b)
{
auto v = OpFrameAdd<E1, OpLiteral<T>>(*static_cast<const E1*>(&a), OpLiteral<T>(b));
return v;
}
template<typename E2, typename T>
auto operator+(T a, OpExpression<E2> const& b)
{
auto v = OpFrameAdd<OpLiteral<T>, E2>(OpLiteral<T>(a), *static_cast<const E2*>(&b));
return v;
}
So my questions are:
Is it possible to augment the design to use the literal in the preferred way? If not, is this is just a limitation of the templates/design I chose? (Casting to OpLiteral is still a lot easier than making a new operator overload for each type and for both sides). More broadly, is there a known (different) design to deal with this problem? Have I applied this design correctly to the problem?
EDIT
With the given design, it doesn't appear possible to accept and convert another type implicitly. Ultimately, it seems the problem can be phrased as: I want to have an operation between 1) A parent class and another parent class; 2) A parent class an any other object; 3) Any class and that parent class. Obviously this is inherently problematic.
For instance, when I attempted to remedy the ambiguous call in the above attempt, it instead results in operations between children of OpExpression becoming a template argument of OpLiteral. This is because instead of resolving the 'correct' operator (i.e. applying operator with both argument types of OpExpression), it will choose the one with the more generic argument type.
The conclusion is that as it is, this is simply a limitation of the design (and for good reason).
However, suppose I have a complete list of all the literal types I would want to use in an expression. If I don't want to create individual template specializations for each one, how would I modify the overloaded operator to use that? Would I instead have to modify the classes of OpExpression?

Related

How to flatten the nested std::optional?

note: this question was briefly marked as a duplicate of this, but it is not an exact duplicate since I am asking about std::optionals specifically. Still a good question to read if you care about general case.
Assume I have nested optionals, something like this(dumb toy example):
struct Person{
const std::string first_name;
const std::optional<std::string> middle_name;
const std::string last_name;
};
struct Form{
std::optional<Person> person;
};
and this spammy function:
void PrintMiddleName(const std::optional<Form> form){
if (form.has_value() && form->person.has_value() && form->person->middle_name.has_value()) {
std::cout << *(*(*form).person).middle_name << std::endl;
} else {
std::cout << "<none>" << std::endl;
}
}
What would be the best way to flatten this optional check?
I have made something like this, it is not variadic, but I do not care that much about that(I can add one more level(overload with membr3) if really necessary, and everything beyond that is terrible code anyway).
template<typename T, typename M>
auto flatten_opt(const std::optional<T> opt, M membr){
if (opt.has_value() && (opt.value().*membr).has_value()){
return std::optional{*((*opt).*membr)};
}
return decltype(std::optional{*((*opt).*membr)}){};
}
template<typename T, typename M1, typename M2>
auto ret_val_helper(){
// better code would use declval here since T might not be
// default constructible.
T t;
M1 m1;
M2 m2;
return ((t.*m1).value().*m2).value();
}
template<typename T, typename M1, typename M2>
std::optional<decltype(ret_val_helper<T, M1, M2>())> flatten_opt(const std::optional<T> opt, M1 membr1, M2 membr2){
if (opt.has_value() && (opt.value().*membr1).has_value()){
const auto& deref1 = *((*opt).*membr1);
if ((deref1.*membr2).has_value()) {
return std::optional{*(deref1.*membr2)};
}
}
return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto flat = flatten_opt(form, &Form::person, &Person::middle_name);
if (flat) {
std::cout << *flat;
}
else {
std::cout << "<none>" << std::endl;
}
}
godbolt
notes:
I do not want to switch away from std::optional to some better optional.
I do not care that much about perf, unless I return a pointer I must make copy(unless arg is temporary) since std::optional does not support references.
I do not care about flatten_has_value function(although it is useful), since if there is a way to nicely flatten the nested optionals there is also a way to write that function.
I know my code looks like it works, but it is quite ugly, so I am wondering if there is a nicer solution.
The operation you're looking for is called the monadic bind operation, and is sometimes spelled and_then (as it is in P0798 and Rust).
You're taking an optional<T> and a function T -> optional<U> and want to get back an optional<U>. In this case the function is a pointer to data member, but it really does behave as a function in this sense. &Form::person takes a Form and gives back an optional<Person>.
You should write this in a way that is agnostic to the kind of function. The fact that it's specifically a pointer to member data isn't really important here, and maybe tomorrow you'll want a pointer to member function or even a free function. So that's:
template <typename T,
typename F,
typename R = std::remove_cvref_t<std::invoke_result_t<F, T>>,
typename U = mp_first<R>>
requires SpecializationOf<R, std::optional>
constexpr auto and_then(optional<T> o, F f) -> optional<U>
{
if (o) {
return std::invoke(f, *o);
} else {
return std::nullopt;
}
}
This is one of the many kinds of function declarations that are just miserable to write in C++, even with concepts. I'll leave it as an exercise to properly add references into there. I choose to specifically write it as -> optional<U> rather than -> R because I think it's important for readability that you can see that it does, in fact, return some kind of optional.
Now, the question is how do we chain this to multiple functions. Haskell uses >>= for monadic bind, but in C++ that has the wrong association (o >>= f >>= g would evaluate f >>= g first and require parentheses). So the next closest chose of operator would be >> (which means something different in Haskell, but we're not Haskell, so it's okay). Or you could implement this borrowing the | model that Ranges does.
So we'd either end up syntactically with:
auto flat = form >> &Form::person >> &Person::middle_name;
or
auto flat = form | and_then(&Form::person)
| and_then(&Person::middle_name);
A different way to compose multiple monadic binds together is an operation that Haskell spells >=>, which is called Kleisli composition. In this case, it takes a function T -> optional<U> and a function U -> optional<V> and produces a function T -> optional<V>. This is something that is exceedingly annoying to write constraints for so I'm just going to skip it, and it would look something like this (using the Haskell operator spelling):
template <typename F, typename G>
constexpr auto operator>=>(F f, G g) {
return [=]<typename T>(T t){
using R1 = std::remove_cvref_t<std::invoke_result_t<F, T>>;
static_assert(SpecializationOf<R1, std::optional>);
using R2 = std:remove_cvref_t<std::invoke_result_t<G, mp_first<R1>>>;
static_assert(SpecializationOf<R2, std::optional>);
if (auto o = std::invoke(f, t)) {
return std::invoke(g, *o);
} else {
// can't return nullopt here, have to specify the type
return R2();
}
};
}
And then you could write (or at least you could if >=> were an operator you could use):
auto flat = form | and_then(&Form::person >=> &Person::middle_name);
Because the result of >=> is now a function that takes a Form and returns an optional<string>.
Let's look at what the optimal form of a flatten function would look like. By "optimal" in this case, I mean the smallest presentation.
Even in the optimal case, at the point of performing the flatten operation, you would need to provide:
The optional<T> object to flatten.
The flatten operation function name.
A list of names, in order, to be indirected from at each flattening step.
Your code is very close to optimal. The only issue is that each name in the "list of names" must contain the typename of the member you're accessing at that level, which is something that hypothetically could be computed using knowledge of T.
C++ has no mechanism to do any better than this. If you want to access a member of an object, you must provide the type of that object. If you want to indirectly do this, C++ allows member pointers, but getting such a pointer requires knowing the type of the object at the point when the member is extracted. Even offsetof gymnastics would require using the type name when you're getting the offset.
Reflection would allow for something better, as you could pass compile-time strings that static reflection could use to fetch member pointers from the type currently in use. But C++20 has no such feature.
You've got a lot of helper functions for something that is fundamentally a chainable operation. And C++ has things for chains: operators. So I'd probably (ab)use operator* for this.
For your specific case, all you need is
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(
const std::optional<class_t>& opt,
const std::optional<member_t> class_t::*member)
{
if (opt.has_value()) return opt.value().*member;
else return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto middle = form * &Form::person * &Person::middle_name;
if (middle) {
std::cout << *middle;
}
else {
std::cout << "<none>" << std::endl;
}
}
But in reality you'd probably also want variants for non-optional members, getter methods, and arbitrary transforms, which I've listed here, though I'm not 100% certain they all compile properly.
//data member
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(const std::optional<class_t>& opt, const std::optional<member_t> class_t::*member) {
if (opt.has_value()) return opt.value().*member;
else return {};
}
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(const std::optional<class_t>& opt, const member_t class_t::*member) {
if (opt.has_value()) return {opt.value().*member};
else return {};
}
//member function
template<class class_t, class return_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, std::optional<return_t>(class_t::*member)()) {
if (opt.has_value()) return opt.value().*member();
else return {};
}
template<class class_t, class return_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, return_t(class_t::*member)()) {
if (opt.has_value()) return {opt.value().*member()};
else return {};
}
//arbitrary function
template<class class_t, class return_t, class arg_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, std::optional<return_t>(*transform)(arg_t&&)) {
if (opt.has_value()) return transform(opt.value());
else return {};
}
template<class class_t, class return_t, class arg_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, return_t(*transform)(arg_t&&)) {
if (opt.has_value()) return {transform(opt.value())};
else return {};
}
http://coliru.stacked-crooked.com/a/26aa7a62f38bbd89

Allow implicit type conversion during template evaluation

I'm writing a wrapper class for C++ types, which allows me to instrument when a wrapped object is constructed, accessed, modified, and destroyed. To make this transparent for the original code, I include implicit conversion functions back to the underlying type, but this fails when a wrapped object is passed directly to a template since implicit conversions aren't evaluated. Here's some code that demonstrates this problem:
#include <utility>
// simplified wrapper class
template <typename T>
class wrap {
T t;
public:
wrap() : t() {}
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}
constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
};
// an example templated function
template <typename T>
bool is_same(const T& t1, const T& t2) { return t1 == t2;}
// second invocation fails due to template substitution failure
bool problem() {
wrap<int> w(5);
return is_same(static_cast<int>(w), 5) && is_same<>(w, 5);
}
I can resolve this manually by performing a static_cast on the wrapped variable at each template call site (as shown in the first invocation), but this doesn't scale well since I'm working with a large code base. Similar questions suggest inlining each template function as a friend function, but this also requires identifying and copying each template, which doesn't scale.
I'd appreciate any advice on how to (1) workaround this conversion problem with templated functions, or (2) otherwise instrument a variable at source-level without this problem.
The fault in this example lies with is_same. It declares that it requires two arguments of the same type, which is a requirement it does not need, and fails to require that type to have an ==, which it does need.
Granted, it is common to find C++ that poorly constrains template functions because it is difficult and verbose to do otherwise. Authors take a practical shortcut. That said, isn't the approach to fix the interface of is_same?
// C++17 version. Close to std::equal_to<>::operator().
template <typename T, typename U>
constexpr auto is_same(T&& t, U&& u)
noexcept(noexcept(std::forward<T>(t) == std::forward<U>(u)))
-> decltype(std::forward<T>(t) == std::forward<U>(u))
{
return std::forward<T>(t) == std::forward<U>(u);
}
With a corrected is_same, the code just works.
There are other examples one can imagine which may require two arguments to have the same type. For example, if the return type depends on the argument type and the return value can come from either:
template <typename T>
T& choose(bool choose_left, T& left, T& right) {
return choose_left ? left : right;
}
This is much rarer. But it might actually require thought to decide whether to use the underlying or wrapper type. If you have this enhanced behavior in the wrapper type, and conditionally use a wrapped value or an underlying value, should the underlying value be wrapped to continue to get the enhanced behavior, or do we drop the enhancement? Even if you could make this silently choose one of those two behaviors, would you want to?
However, you can still make it easier to get the value than to say static_cast<T>(...), for example by providing an accessor:
// given wrap<int> w and int i
is_same(w.value(), 5);
choose_left(true, w.value(), i);
I have a few other important comments:
wrap() : t() {}
This requires T be default constructible. = default does the right thing.
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}
These are not explicit. A T is implicitly convertible to a wrap<T> and vice versa. This does not work well in C++. For example, true ? w : i is not well-formed. This causes std::equality_comparable_with<int, wrap<int>> to be false, which would be a reasonable requirement for is_same. Wrapper types should probably be explicitly constructed, and can be implicitly converted to the underlying type.
constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
These are not ref-qualified, so they return lvalue references even if the wrapper is an rvalue. That seems ill-advised.
Finally, construction and conversion only take into account the exact type T. But any place T is used, it might be implicitly converted from some other type. And two conversions are disallowed in C++. So for a wrapper type, one has a decision to make, and that often means allowing construction from anything a T is constructible from.
With a pointer wrapper function it can work, if you treat the "inner" guy as a pointer.
This is not a complete solution, but should be a good starting point for you (for instance, you need to carefully write the copy and move ctors).
You can play with this code in here.
Disclaimer: I took the idea from Andrei Alexandrescu from this presentation.
#include <iostream>
using namespace std;
template <typename T>
class WrapperPtr
{
T * ptr;
public:
WrapperPtr(const WrapperPtr&){
// ???
}
WrapperPtr(WrapperPtr&&) {
// ???
}
WrapperPtr(const T & other)
: ptr(new T(other)) {}
WrapperPtr(T * other)
: ptr(other) {}
~WrapperPtr()
{
// ????
delete ptr;
}
T * operator -> () { return ptr; }
T & operator * () { return *ptr; }
const T & operator * () const { return *ptr; }
bool operator == (T other) const { other == *ptr; }
operator T () { return *ptr; }
};
// an example templated function
template <typename T>
bool my_is_same(const T& t1, const T& t2) { return t1 == t2;}
bool problem() {
WrapperPtr<int> w(5);
return my_is_same(static_cast<int>(w), 5) && my_is_same(*w, 5);
}

Binary Operator for Template Class Doesn't Resolve Implicit Conversion

Consider the following classes, where the first is templated. Both are meant to hold a numeric value.
template<typename T>
struct foo
{
foo(T val) : val{ val } {}
T val;
};
struct bar
{
bar(double val) : val{ val } {}
double val;
};
I want to define a way to add these classes together to get a new one with a different value.
template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
return foo<T>(a.val + b.val);
}
bar operator+(bar a, bar b)
{
return bar(a.val + b.val);
}
When I use these operators with implicit conversion, the operator using object of type foo doesn't use the implicit conversion on the double value to apply my overloaded operator, even though it can do it for the non-template class. The result is that there is no operator matching the types in that expression.
int main()
{
foo<double> foo_value(11.0);
bar bar_value(11.0);
foo<double> ev1 = foo_value + 1.0; // no operator matches these operands
bar ev2 = bar_value + 1.0;
}
Does the operator have to be explicitly instantiated first? If so, a) how does that look like, and b) why isn't the instantiation done implicitly, if it can be done when initializing an object of type foo<double>?
If the standard doesn't support any sort of resolution without explicitly casting 1.0 to a value of type foo<double>, I presume the only other possibility is defining operator overloads for each type I want to use like that (for both lhs and rhs)?
The thing you have to remember about templates is that they will not do a conversion for you. All they do is try and figure out the types things are, and if that jives with template parameters, then it will stamp out the function and call it.
In you case when you do
foo_value + 1.0
the compiler goes okay, lets see if we have any operator + that will work for this. It finds
template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
return foo<T>(a.val + b.val);
}
and then it tries to figure out what T is so it can stamp out a concrete function. It looks at foo_value, sees it is a foo<double> so it says for the first parameter T needs to be a double. Then it looks at 1.0 and goes okay, I have a double and that is when you run into a problem. The compiler can't deduce what T should be for b because it expects a foo<some_type>, but got a double instead. Because it can't deduce a type, your code fails to compile.
In order to get the behavior you want you would need to add
template<typename T>
foo<T> operator+(foo<T> a, T b)
{
return foo<T>(a.val + b);
}
Which lets you add a T to a foo<T>, or better yet
template<typename T, typename U>
foo<T> operator+(foo<T> a, U b)
{
return foo<T>(a.val + b);
}
Which lets you add anything to a foo<T> (foo<double> + int for instance where the first version would not allow that)

how to use the type of compile time constant primitive

How to use the type of a compile time constant primitive as type declaration for other variables?
I am trying to do some template metaprogramming in c++ for SI unit conversion. It comes down to how to automatically determine which primitive precision I need after one plus operator. For example:
template<typename Precision>
class Unit {
public:
Unit(Precision v) : value(v) {}
Precision value;
};
template<typename Precision1, typename Precision2>
struct PrecisionTransform {
constexpr static auto test = (Precision1)1 * (Precision2)1; // Compile time constant
using Type = Precision1; // TODO: ideally typeof(test)
};
template<typename Precision1, typename Precision2>
Unit<PrecisionTransform<Precision1, Precision2>::Type> operator+(const Unit<Precision1>& x, const Unit<Precision2>& y)
{
return Unit<PrecisionTransform<Precision1, Precision2>::Type>(x.value + y.value);
}
int main()
{
Unit<double> a = 2.0;
Unit<float> b = 1.0f;
auto c = a + b;
return 0;
}
or in simple terms, can some thing like this happen?
float a = 1;
typeof(a) b = 2;
It seems quite possible since I've gone this far. But I am not sure how to use
You almost got it. As max66 already pointed out, use decltype. First of all, you can replace your PrecisionTransform class with the follwing type alias (you have to #include <utility> for this):
template <typename Precision1, typename Precision2>
using TransformType = decltype(std::declval<Precision1>() * std::declval<Precision2>());
The std::declval<XYZ>() is just a more generic way of saying (Precision1)1 which allows you to also use types that don't have accessible constructors (in your case irrelevant as you only use primitives).
Your operator+ is then changed to:
template<typename Precision1, typename Precision2>
Unit<TransformType<Precision1, Precision2>> operator+(const Unit<Precision1>& x, const Unit<Precision2>& y)
{
return Unit<TransformType<Precision1, Precision2>>(x.value + y.value);
}
Note that you got a typo in your version of operator+ (both operands used Precision1).
As you can see here, the major compilers agree on this.

Express general monadic interface (like Monad class) in C++

Is it even possible to express a sort of monad" C++ ?
I started to write something like this, but stuck:
#include <iostream>
template <typename a, typename b> struct M;
template <typename a, typename b> struct M {
virtual M<b>& operator>>( M<b>& (*fn)(M<a> &m, const a &x) ) = 0;
};
template <typename a, typename b>
struct MSome : public M<a> {
virtual M<b>& operator>>( M<a>& (*fn)(M<a> &m, const a &x) ) {
return fn(*this, x);
}
private:
a x;
};
M<int, int>& wtf(M<int> &m, const int &v) {
std::cout << v << std::endl;
return m;
}
int main() {
// MSome<int> v;
// v >> wtf >> wtf;
return 0;
}
but faced the lack of polymorphism. Actually it may be my uncurrent C++ 'cause I used it last time 8 years ago. May be it possible to express general monadic interface using some new C++ features, like type inference. It's just for fun and for explaining monads to non-haskellers and non-mathematicians.
C++' type system is not powerful enough to abstract over higher-kinded types, but since templates are duck-typed you may ignore this and just implement various Monads seperately and then express the monadic operations as SFINAE templates. Ugly, but the best it gets.
This comment is bang on the money. Time and time again I see people trying to make template specializations 'covariant' and/or abuse inheritance. For better or for worse, concept-oriented generic programming is in my opinion* saner. Here's a quick demo that will use C++11 features for brevity and clarity, although it should be possible to implement the same functionality in C++03:
(*: for a competing opinion, refer to "Ugly, but the best it gets" in my quote!)
#include <utility>
#include <type_traits>
// SFINAE utility
template<typename...> struct void_ { using type = void; };
template<typename... T> using Void = typename void_<T...>::type;
/*
* In an ideal world std::result_of would just work instead of all that.
* Consider this as a write-once (until std::result_of is fixed), use-many
* situation.
*/
template<typename Sig, typename Sfinae = void> struct result_of {};
template<typename F, typename... Args>
struct result_of<
F(Args...)
, Void<decltype(std::declval<F>()(std::declval<Args>()...))>
> {
using type = decltype(std::declval<F>()(std::declval<Args>()...));
};
template<typename Sig> using ResultOf = typename result_of<Sig>::type;
/*
* Note how both template parameters have kind *, MonadicValue would be
* m a, not m. We don't whether MonadicValue is a specialization of some M<T>
* or not (or derived from a specialization of some M<T>). Note that it is
* possible to retrieve the a in m a via typename MonadicValue::value_type
* if MonadicValue is indeed a model of the proper concept.
*
* Defer actual implementation to the operator() of MonadicValue,
* which will do the monad-specific operation
*/
template<
typename MonadicValue
, typename F
/* It is possible to put a self-documenting assertion here
that will *not* SFINAE out but truly result in a hard error
unless some conditions are not satisfied -- I leave this out
for brevity
, Requires<
MonadicValueConcept<MonadicValue>
// The two following constraints ensure that
// F has signature a -> m b
, Callable<F, ValueType<MonadicValue>>
, MonadicValueConcept<ResultOf<F(ValueType<MonadicValue>)>>
>...
*/
>
ResultOf<MonadicValue(F)>
bind(MonadicValue&& value, F&& f)
{ return std::forward<MonadicValue>(value)(std::forward<F>(f)); }
// Picking Maybe as an example monad because it's easy
template<typename T>
struct just_type {
using value_type = T;
// Encapsulation omitted for brevity
value_type value;
template<typename F>
// The use of ResultOf means that we have a soft contraint
// here, but the commented Requires clause in bind happens
// before we would end up here
ResultOf<F(value_type)>
operator()(F&& f)
{ return std::forward<F>(f)(value); }
};
template<typename T>
just_type<T> just(T&& t)
{ return { std::forward<T>(t) }; }
template<typename T>
just_type<typename std::decay<T>::type> make_just(T&& t)
{ return { std::forward<T>(t) }; }
struct nothing_type {
// Note that because nothing_type and just_type<T>
// are part of the same concept we *must* put in
// a value_type member type -- whether you need
// a value member or not however is a design
// consideration with trade-offs
struct universal { template<typename T> operator T(); };
using value_type = universal;
template<typename F>
nothing_type operator()(F const&) const
{ return {}; }
};
constexpr nothing_type nothing;
It is then possible to write something like bind(bind(make_just(6), [](int i) { return i - 2; }), [](int i) { return just("Hello, World!"[i]); }). Be aware that the code in this post is incomplete in that the wrapped values aren't forwarded properly, there should be errors as soon as const-qualified and move-only types are involved. You can see the code in action (with GCC 4.7) here, although that might be a misnomer as all it does is not trigger assertions. (Same code on ideone for future readers.)
The core of the solution is that none of just_type<T>, nothing_type or MonadicValue (inside bind) are monads, but are types for some monadic values of an overarching monad -- just_type<int> and nothing_type together are a monad (sort of -- I'm putting aside the matter of kind right now, but keep in mind that it's possible to e.g. rebind template specializations after the fact, like for std::allocator<T>!). As such bind has to be somewhat lenient in what it accepts, but notice how that doesn't mean it must accept everything.
It is of course perfectly possible to have a class template M such that M<T> is a model of MonadicValue and bind(m, f) only ever has type M<U> where m has type M<T>. This would in a sense make M the monad (with kind * -> *), and the code would still work. (And speaking of Maybe, perhaps adapting boost::optional<T> to have a monadic interface would be a good exercise.)
The astute reader would have noticed that I don't have an equivalent of return here, everything is done with the just and make_just factories which are the counterparts to the Just constructor. This is to keep the answer short -- a possible solution would be to write a pure that does the job of return, and that returns a value that is implicitly convertible to any type that models MonadicValue (by deferring for instance to some MonadicValue::pure).
There are design considerations though in that the limited type deduction of C++ means that bind(pure(4), [](int) { return pure(5); }) would not work out of the box. It is not, however, an insurmountable problem. (Some outlines of a solution are to overload bind, but that's inconvenient if we add to the interface of our MonadicValue concept since any new operation must also be able to deal with pure values explicitly; or to make a pure value a model of MonadicValue as well.)
I would do it like this:
template<class T>
class IO {
public:
virtual T get() const=0;
};
template<class T, class K>
class C : public IO<K> {
public:
C(IO<T> &io1, IO<K> &io2) : io1(io1), io2(io2) { }
K get() const {
io1.get();
return io2.get();
}
private:
IO<T> &io1;
IO<K> &io2;
};
int main() {
IO<float> *io = new YYYY;
IO<int> *io2 = new XXX;
C<float,int> c(*io, *io2);
return c.get();
}