Skip to content

Instantly share code, notes, and snippets.

@smoofra
Created October 8, 2019 20:09
Show Gist options
  • Save smoofra/091d1f433556c295d0dc033fc05bd2fc to your computer and use it in GitHub Desktop.
Save smoofra/091d1f433556c295d0dc033fc05bd2fc to your computer and use it in GitHub Desktop.
#include <iostream>
#include <stdio.h>
// better Expected monad in C++, using std::invoke
struct Error {};
template<typename T> class Expected;
template<typename T> struct IdempotentExpectedStruct {
typedef Expected<T> type;
};
template<typename T>
struct IdempotentExpectedStruct<Expected<T>> {
typedef Expected<T> type;
};
template<typename T>
using IdempotentExpected = typename IdempotentExpectedStruct<T>::type;
template <class T> class Expected {
public:
using value_type = T;
bool error;
T value;
Expected (T t) : value(t) {
error = false;
}
Expected (Error e) {
error = true;
}
operator bool() {
return !error;
}
T &get() {
return value;
}
Error takeError() {
return Error();
}
template<typename F, typename... Args>
IdempotentExpected<typename std::invoke_result<F, T, Args...>::type> bind(F &&f, Args && ... args) {
if (!*this)
return takeError();
return std::invoke<F, T&, Args...>(std::forward<F>(f), get(), std::forward<Args>(args)...);
}
};
struct Foo {
int x;
Foo (int a) {
x = a;
}
int Baz() {
return x+1;
}
int Bar(int y) {
return 100 * x + y;
}
Expected<float> Quux(int y, int z) {
return 10000 * x + 100*y + z;
}
};
int main() {
Expected<int> e(42);
std::cout << e.bind([](int x) -> Expected<float> {
return x / 10.0;
}).get() << std::endl;
std::cout << e.bind([](int x) -> float {
return x * 10.0;
}).get() << std::endl;
std::cout << Expected<Foo>(Foo(99)).bind(&Foo::Baz).get() << std::endl;
std::cout << Expected<Foo>(Foo(99)).bind(&Foo::Bar, 3).get() << std::endl;
std::cout << Expected<Foo>(Foo(99)).bind(&Foo::Quux, 6, 7).get() << std::endl;
std::cout << e.bind([](int x, float y) -> Expected<float> {
return x / 10.0 + y ;
}, 0.1).get() << std::endl;
std::cout << e.bind([](int x, float y) -> float {
return x * 10.0 + y;
}, 0.2).get() << std::endl;
Expected<const std::string> c("foo");
std::cout << c.bind([](std::string s) { return s + s; }).get() << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment