I want to build function, like as:
template< int ... values>
constexpr bool check( int i ) noexcept
{
switch(i)
{
case values[0]: case values[1]: ... case values[n-1] : // only illustrated.
return true;
default: return false;
}
}
Can I make that function?
UPDATE: thanks, now i know how to implement:
template< int ... values> struct checker;
template< int head, int ... tail> struct checker<head, tail...>
{
static constexpr bool apply( int i ) noexcept {
return i == head || checker<tail...>::apply(i);
}
};
template<> struct checker<>
{
static constexpr bool apply( int ) noexcept { return false; }
};
template< int ... values >
constexpr bool check(int i) noexcept { return checker<values...>::apply(i); }
UPDATE2: I don't know, it's good or not, but i found this solution :
template<size_t N>
constexpr bool any_of( bool( && array)[N], size_t index = 0) noexcept
{
return (index == N ) ? false
: ( array[index] || any_of( std::forward< decltype(array)>(array), 1+index) );
}
template< int ... values >
constexpr bool check(int i) noexcept
{
using list = bool[sizeof...(values)];
return any_of( list{ ( i == values) ... } );
}
template<>
constexpr bool check <>(int i) noexcept { return false; }
I don't think it's possible to use the switch syntax in any way. But this should work:
template < int head, int ... values >
struct checker
{
static constexpr bool value(int i) noexcept
{ return i == head || checker<values...>::value(i); }
};
template < int head >
struct checker<head>
{
static constexpr bool value(int i) noexcept
{ return i == head; }
};
template< int ... values>
constexpr bool check( int i ) noexcept
{
return checker<values...>::value(i);
}
Live example
Related
Can't use variant.index() in constexpr statements so need to iterate variant and return true if it can cast to some type or false if it's emtpy or contains zero value. Try this code, but seems index sequence is not variadic type and ... operator not available in this case.
template <typename T>
bool has_value(T value) noexcept {
if constexpr (std::is_convertible_v <T, bool>) {
return value;
}
else if constexpr (is_variant_v<T>) {
constexpr size_t N = std::variant_size_v<decltype(value)>;
using variant_sequence = typename std::make_index_sequence<0, N-1>::type;
bool __has_value = (( std::get<variant_sequence>(value), true) || variant_sequence... ) ;
return __has_value;
}
return false;
}
I think you want:
template <typename T>
bool has_value(T value) noexcept {
if constexpr (std::is_convertible_v <T, bool>) {
return value;
} else if constexpr (is_variant_v<T>) {
return std::visit([](const auto& elem){ return has_value(elem); }, value);
}
return false;
}
I have a variadic class template
template <size_t ...T>
struct Foo
{
std::vector<size_t> t;
bool IsEqual()
{
//??
}
};
which I want to use like:
Foo<1,2,3,4> foo;
foo.data = {1,2,3,4};
foo.IsEqual();
How can I implement IsEqual to iterate and compare every element of the vector and return false / true if the elements are in the same order as the template parameters?
Use the index sequence trick:
bool IsEqual()
{
return t.size() == sizeof...(T) &&
IsEqual(std::make_index_sequence<sizeof...(T)>{});
}
with:
template <size_t... Is>
bool IsEqual(std::index_sequence<Is...> ) {
bool valid = true;
using expander = int[];
expander{0,
(valid = valid && t[Is] == T,
0)...
};
return valid;
}
Could even do this in one function by taking advantage of the fact that every value computation and side effect in an initializer-clause is sequenced before the next one by doing this in one go:
bool IsEqual()
{
if (t.size() == sizeof...(T)) {
auto it = t.begin();
bool valid = true;
using expander = int[];
expander{0,
(valid = valid && *it++ == T,
0)...
};
return valid;
}
else {
return false;
}
}
Simply unpack template arguments.
template <size_t ...T>
struct Foo
{
std::vector<size_t> t;
bool IsEqualTemplate(size_t index)
{
return true;
}
template <typename FIRSTARG, typename ...OTHERARGS>
bool IsEqualTemplate(size_t index, FIRSTARG firstArg, OTHERARGS... otherArgs)
{
return t[index] == firstArg && IsEqualTemplate(index + 1, otherArgs...);
}
bool IsEqual()
{
return t.size() == sizeof...(T) ? IsEqualTemplate(0, T...) : false;
}
};
Let's say i have a class that simply performs addition for any type T. I want to add an optional range check (based on a template parameter of type bool), that will check whether the result of the addition belongs in a given range, or else it will throw.
One way of doing this, is wrapping all basics of the class in a base class and then specialize on the boolean template parameter. Something like:
// The base class; holds a starting value to add to and a maximum value
template<typename T>
class DummyImpl
{
private:
T mval, mmax;
public:
constexpr explicit DummyImpl(T x, T max_x) noexcept
: mval{x}, mmax{max_x}
{};
// base class; use a virtual destructor
virtual ~DummyImpl() {};
T max() const noexcept {return mmax;}
T val() const noexcept {return mval;}
};
// The "real" class; parameter B denotes if we want (or not)
// a range check
template<typename T, bool B>
class Dummy : DummyImpl<T> {};
// Specialize: we do want range check; if sum not in range
// throw.
template<typename T>
class Dummy<T, true> : DummyImpl<T>
{
public:
explicit Dummy(T x, T max_x) noexcept : DummyImpl<T>(x, max_x) {};
T add(T x) const noexcept( !true )
{
T ret_val = x + DummyImpl<T>::val();
if (ret_val < 0 || ret_val > DummyImpl<T>::max()) {
throw 1;
}
return ret_val;
}
};
// Specialize for no range check.
template<typename T>
class Dummy<T, false> : DummyImpl<T>
{
public:
explicit Dummy(T x, T max_x) noexcept : DummyImpl<T>(x, max_x) {};
T add(T x) const noexcept( !false )
{
return x + DummyImpl<T>::val();
}
};
Now the user can write code like:
int main()
{
Dummy<float,false> d(0, 1000); //no range check; never throw
std::cout <<"\nAdding 156.7 gives " << d.add(156.7);
std::cout <<"\nAdding 3156.7 gives " << d.add(3156.7);
std::cout <<"\n";
return 0;
}
Is there a way of doing this without using inheritance? I would suppose that using a nested class would be more efficient, but the following code
does not compile.
template<typename T, bool RC>
class Dummy
{
private:
T mval, mmax;
// parameter S is only used to enable partial specialization on
// parameter I
template<bool I, typename S> struct add_impl {};
template<typename S> struct add_impl<true, S>
{
T operator()(T x) const noexcept( !true )
{
T ret_val = x + mval;
if (ret_val < 0 || ret_val > mmax) {throw 1;}
return ret_val;
}
};
template<typename S> struct add_impl<false, S>
{
T operator()(T x) const noexcept( !false )
{
return x + mval_ref;
}
};
public:
constexpr explicit Dummy(T x, T max_x) noexcept
: mval{x}, mmax{max_x}
{};
void bar() const { std::cout << "\nin Base."; }
T max() const noexcept {return mmax;}
T val() const noexcept {return mval;}
T add(T x) const noexcept( !RC )
{
return add_impl<RC, T>()(x);
}
};
int main()
{
Dummy<float,false> d(0, 1000);
std::cout <<"\nAdding 156.7 gives " << d.add(156.7);
std::cout <<"\nAdding 3156.7 gives " << d.add(3156.7);
std::cout <<"\n";
return 0;
}
It fails with an error message (in g++):
error: invalid use of non-static data member ‘Dummy<float, false>::mval’
Is there a way around this? If so, is it more efficient than the first solution? Will the nested class add size to any instance of Dummy? Is there a more elegant design/implementation?
I would just dispatch on RC. And making it a type:
template<typename T, bool RC>
class Dummy
{
private:
using do_range_check = std::integral_constant<bool, RC>;
T mval, mmax;
};
With that:
T add(T x) const {
return add(x, do_range_check{});
}
private:
T add(T x, std::false_type /* range_check */) {
return x + mval;
}
T add(T x, std::true_type /* range_check */) {
T ret_val = x + mval;
if (ret_val < 0 || ret_val > mmax) {throw 1;}
return ret_val;
}
The advantage there is that this is a normal member function - you're not offloading onto some other type that you need to pass members around to. And you don't need to specialize... anything. Which is great.
I usually try to not use boolean flags in functions to switch behavior.
You can pass the range-check as a policy instead of the bool template parameter, in the style of policy-based design. The policies do not need a be related by inheritance, because there are no constraints on the type of the template arguments except the ones derived from using them. You can put in any type you like as long as it provides the necessary interface. This way, I can define two independent classes without any (inheritance) relationship, and use both of them as template parameters. The drawback is that Dummy<float, X> and Dummy<float, Y> are two different, unrelated types and you cannot e.g. assign an instance of the first type to an instance of the second one without defining a template assignment operator.
#include <stdexcept>
template<typename T>
struct NoMaxCheck
{
NoMaxCheck(T) {}
void check(T) const noexcept {}
};
template<typename T>
struct ThresholdChecker
{
ThresholdChecker(T value) : mMax(value) {}
void check(T value) const
{
if (value < 0 || mMax < value) {
throw std::out_of_range("");
}
}
private:
T mMax;
};
template<typename T, typename CheckPolicy>
class Dummy
{
private:
T mVal;
CheckPolicy mThresholdChecker;
public:
explicit Dummy(T x, T max_x) noexcept : mVal(x), mThresholdChecker(max_x) {};
T add(T x) const noexcept(noexcept(mThresholdChecker.check(x)))
{
T ret_val = x + mVal();
mThresholdChecker.check(ret_val);
return ret_val;
}
};
template<typename T, template<typename> typename CheckPolicy>
class DummyEmptyBaseClasss: private CheckPolicy<T>
{
private:
T mVal;
public:
explicit DummyEmptyBaseClasss(T x, T max_x) noexcept:
CheckPolicy<T>(max_x),
mVal(x) {};
T add(T x) const noexcept(noexcept(check(x)))
{
T ret_val = x + mVal();
check(ret_val);
return ret_val;
}
};
int foo()
{
Dummy<float,NoMaxCheck<float>> unchecked(0, 1000);
Dummy<float,ThresholdChecker<float>> checked(0, 1000);
static_assert( sizeof(DummyEmptyBaseClasss<float, NoMaxCheck>) == sizeof(float), "empty base class optimization");
}
You can simplify it more with template-template parameters to get rid of the redundant float parameter. DummyEmptyBaseClass shows this.
Compilers are quite good at elimination of obviously dead code (such as that arising from boolean template parameters). I'd therefore go with the most straightforward solution:
template<typename T, bool RC>
class Dummy
{
private:
T mval, mmax;
public:
T add(T x) const noexcept( !RC )
{
T ret_val = x + val();
if (RC && (ret_val < 0 || ret_val > DummyImpl<T>::max())) {
throw 1;
}
return ret_val;
}
//...
};
I would be extremely surprised if any runtime code were generated for the instantiation where RC == false. In fact, I would consider that an optimiser bug.
You may use composition
template<typename T, bool B> struct ThresholdChecker;
template<typename T>
struct ThresholdChecker<T, true>
{
ThresholdChecker(T value) : mMax(value) {}
void check(T value) const
{
if (value < 0 || mMax < value) {
throw std::out_of_range("");
}
}
private:
T mMax;
};
template<typename T>
struct ThresholdChecker<T, false>
{
ThresholdChecker(T) {}
void check(T) const noexcept {}
};
template<typename T, bool RC>
class Dummy
{
private:
T mval;
ThresholdChecker<T, RC> mThresholdChecker;
public:
explicit Dummy(T x, T max_x) noexcept : mVal(x), mThresholdChecker(max_x) {};
T add(T x) const noexcept(noexcept(mThresholdChecker.check(x)))
{
T ret_val = x + val();
mThresholdChecker.check(ret_val);
return ret_val;
}
//...
};
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Extending enums in C++?
I am using a library which defines its own set of errors as an enum type.
enum error_type {...}
The library also has a function which takes that enum type, and prints the error.
void set_status(error_type new_error)
If I want to define my own error, and give it to the set_status function, is it possible to extend the error_type enum somehow, or maybe override it?
There might be some sharp edges, but I think this should work for you:
#include<iostream>
// Helper struct
template<typename T, int N, typename... LIST>
struct whereInType {
static const int index = -1;
};
template<typename T, int N, typename HEAD, typename... TAIL>
struct whereInType<T,N,HEAD,TAIL...> {
static const int index = whereInType<T, N+1, TAIL...>::index;
};
template<typename T, int N, typename... TAIL>
struct whereInType<T,N,T,TAIL...> {
static const int index = N;
};
// The actual union type
template<typename... ENUMS>
class enum_union {
public:
template<typename ENUM>
constexpr enum_union(ENUM val) :
which_enum(whereInType<ENUM,0,ENUMS...>::index),
value(val) {}
constexpr operator long long(){
return static_cast<long long>(which_enum)<<32 | value;
}
template<typename ENUM, int IGNORE=0>
constexpr bool operator==(const ENUM& e) {
return *this == enum_union<ENUMS...>(e);
}
template<int IGNORE=0>
constexpr bool operator==(const enum_union<ENUMS...>& oth) {
return which_enum==oth.which_enum && value==oth.value;
}
template<typename T>
constexpr bool operator!=(const T& oth) {
return !(*this == oth);
}
private:
int which_enum;
int value;
};
// An example usage
enum normal_errors {
E_OUTOFMEMORY,
E_IOERROR
};
enum weird_errors {
E_OUTOFAARDVARKS,
E_DIVIDEBYCUCUMBER
};
typedef enum_union<normal_errors, weird_errors> any_error;
// Some tests
void print(any_error e) {
switch(e) {
case any_error(E_OUTOFMEMORY):
std::cout << "Out of Memory\n";
break;
case any_error(E_IOERROR):
std::cout << "I/O Error\n";
break;
case any_error(E_OUTOFAARDVARKS):
std::cout << "WE NEED AARDVARKS!!! NOW!!!!!\n";
break;
case any_error(E_DIVIDEBYCUCUMBER):
std::cout << "please reinstall universe\n";
break;
}
}
main(){
print(E_OUTOFMEMORY);
print(E_IOERROR);
print(E_OUTOFAARDVARKS);
print(E_DIVIDEBYCUCUMBER);
if (any_error(E_OUTOFMEMORY) == E_OUTOFAARDVARKS) {
std::cout<<"bad\n";
}else{
std::cout<<"good\n";
}
if (any_error(E_OUTOFMEMORY) != E_OUTOFAARDVARKS) {
std::cout<<"good\n";
}else{
std::cout<<"bad\n";
}
if (any_error(E_OUTOFMEMORY) == E_OUTOFMEMORY) {
std::cout<<"good\n";
}else{
std::cout<<"bad\n";
}
if (any_error(E_OUTOFMEMORY) != E_OUTOFMEMORY) {
std::cout<<"bad\n";
}else{
std::cout<<"good\n";
}
}
I am trying to implement the Maybe monad from Haskell using the lambda functions in C++11 and templates. Here's what I have so far
#include<functional>
#include<iostream>
using namespace std;
template<typename T1>
struct Maybe
{
T1 data;
bool valid;
};
template<typename T1, typename T2>
Maybe<T2> operator>>=(Maybe<T1> t, std::function < Maybe<T2> (T1)> &f)
{
Maybe<T2> return_value;
if(t.valid == false)
{
return_value.valid = false;
return return_value;
}
else
{
return f(t.data);
}
}
int main()
{
Maybe<int> x = {5, true};
Maybe<int> y = {29, false};
auto z = [](int a) -> Maybe<int>
{
Maybe<int> s;
s.data = a+1;
s.valid = true;
return s;
};
Maybe<int> p = (x >>= z);
Maybe<int> q = (y >>= z);
cout<<p.data<<' '<<p.valid<<endl;
cout<<q.data<<' '<<q.valid<<endl;
}
When it comes to the actual >>= call, I am getting a compiler error saying that no match found for >>= operator. Is my understanding of C++11's lambda functions failing me here?
The type of a lambda isn't a specialization of std::function. It's some unamed type. There is a conversion to std::function, but that means type deduction won't work for it. So, in this call:
Maybe<int> p = (x >>= z);
The type T2 can't be deduced:
Maybe<T2> operator>>=(Maybe<T1> t, std::function < Maybe<T2> (T1)> &f)
Store the lambda in a std::function variable from the start, and it should work:
std::function < Maybe<int> (int)> z = [](int a) -> Maybe<int> { ... };
However, it's probably easier to accept any kind of function object. That way you can still use auto for the lambda.
template<typename T1, typename F>
typename std::result_of<F(T1)>::type
operator>>=(Maybe<T1> t, F&& f) {
... std::forward<F>(f)(t.data);
}
The following works for me: I use decltype to infer the type returned by the lambda:
template<typename T1, typename Func>
auto operator>>=(Maybe<T1> t, Func f) -> decltype(f(t.data))
{
decltype(f(t.data)) return_value;
if(t.valid == false)
{
return_value.valid = false;
return return_value;
}
else
{
return f(t.data);
}
}
EDIT
For type safety :
template<typename T1>
struct Maybe
{
T1 data;
bool valid;
static const bool isMaybe = true;
};
template<typename T1, typename Func>
auto operator>>=(Maybe<T1> t, Func f) -> decltype(f(t.data))
{
typedef decltype(f(t.data)) RT;
static_assert(RT::isMaybe, "F doesn't return a maybe");
...
Here's my maybe "monad" that I use quite often in my C++ projects (disclaimer: see the comments below). It's insofar more like the Haskell Maybe than your implementation as it only holds an object in the just case (points mobj on it), not wasting space if it's nothing. This also allows it to use of C++11 move semantics, to avoid unnecessary copies. The return types of fmap (fmapped member function) and >>= are deduced with decltype.
template<typename DataT>
class maybe;
template<typename DataT>
maybe<DataT> just(const DataT &obj);
struct nothing_object{nothing_object(){}};
const nothing_object nothing;
//template class objects of which may or may not contain some given
// data object. Inspired by Haskell's Maybe monad.
template<typename DataT>
class maybe {
DataT *obj;
public:
class iterator {
DataT *mobj;
explicit iterator(DataT *init):mobj(init){}
public:
iterator():mobj(nullptr){}
iterator(const iterator &cp):mobj(cp.mobj){}
bool operator!=(const iterator &other)const{return mobj!=other.mobj;}
DataT &operator*() const{return *mobj;}
iterator &operator++(){ mobj=nullptr; return *this; }
friend class maybe;
};
class const_iterator {
const DataT *mobj;
explicit const_iterator(const DataT *init):mobj(init){}
public:
const_iterator():mobj(nullptr){}
const_iterator(const const_iterator &cp):mobj(cp.mobj){}
bool operator!=(const const_iterator &other)const{return mobj!=other.mobj;}
const DataT &operator*() const{return *mobj;}
const_iterator &operator++(){ mobj=nullptr; return *this; }
friend class maybe;
};
iterator begin(){return iterator(obj);}
iterator end(){return iterator();}
const_iterator begin()const{return const_iterator(obj);}
const_iterator end()const{return const_iterator();}
const_iterator c_begin()const{return const_iterator(obj);}
const_iterator c_end()const{return const_iterator();}
bool is_nothing()const{return obj==nullptr;}
void make_nothing(){delete obj; obj=nullptr;}
bool is_just()const{return obj!=nullptr;}
template<typename CpDataT>
void with_just_assign(CpDataT &mdftg)const{if(obj) mdftg=*obj;}
DataT &from_just(){return *obj;}
DataT &operator*(){return *obj;}
const DataT &from_just()const{return *obj;}
const DataT &operator*()const{return *obj;}
template<typename CmpDataT>
bool operator==(const maybe<CmpDataT> &cmp)const{
return is_just()==cmp.is_just() && (is_nothing() || *obj==*cmp.obj); }
template<typename CmpDataT>
bool operator!=(const maybe<CmpDataT> &cmp)const{
return is_just()!=cmp.is_just() || (is_just() && *obj!=*cmp.obj); }
bool operator==(const nothing_object &n)const{return obj==nullptr;}
bool operator!=(const nothing_object &n)const{return obj!=nullptr;}
template<typename MpFnT>
auto fmapped(MpFnT f) const -> maybe<decltype(f(*obj))> {
return obj? just(f(*obj)) : nothing; }
template<typename MonadicFn>
auto operator>>=(MonadicFn f) const -> decltype(f(*obj)) {
return obj? f(*obj) : nothing; }
template<typename ReplaceDT>
auto operator>>(const maybe<ReplaceDT> &r) const -> maybe<ReplaceDT> {
return obj? r : nothing; }
auto operator>>(const nothing_object &n) const -> maybe<DataT> {
return nothing; }
maybe(const nothing_object &n):obj(nullptr){}
template<typename CpDataT>
explicit maybe(const CpDataT &cobj):obj(new DataT(cobj)){}
template<typename CpDataT>
maybe &operator=(const CpDataT &cobj){delete obj; obj=new DataT(cobj); return *this;}
template<typename CpDataT>
maybe(const maybe<CpDataT> &cp):obj(cp.is_just()?new DataT(cp.from_just()):nullptr){}
template<typename CpDataT>
maybe &operator=(const maybe<CpDataT> &cp){
delete obj; obj = cp.is_just()? new DataT(cp.from_just()) : nullptr; return *this;}
maybe(maybe<DataT> &&mv):obj(mv.obj){mv.obj=nullptr;}
maybe &operator=(maybe<DataT> &&mv) {
delete obj; obj=mv.obj; mv.obj=nullptr; return *this; }
~maybe(){delete obj;}
};
template<typename DataT>
auto just(const DataT &obj) -> maybe<DataT> {return maybe<DataT>(obj);}
template<typename MpFnT, typename DataT> // represents Haskell's <$> infix
auto operator^(MpFnT f, const maybe<DataT> &m) -> decltype(m.fmapped(f)) {
return m.fmapped(f);
}
template<typename DataT>
auto joined(const maybe<maybe<DataT>> &m) -> maybe<DataT> {
return m.is_just()? m.from_just() : nothing;
}
template<typename DataT>
auto maybe_yes(const std::pair<DataT,bool>& mbcst) -> maybe<DataT> {
return mbcst.second ? just(mbcst.first) : nothing;
}
template<typename DataT>
auto maybe_not(const std::pair<DataT,bool>& mbcst) -> maybe<DataT> {
return !mbcst.second ? just(mbcst.first) : nothing;
}
The somewhat strange-seeming begin and end iterators allow it to be used in C++11 range-based for loops:
maybe<int> a = just(7), b = nothing;
for (auto&i: a) std::cout << i;
for (auto&i: b) std::cout << i;
outputs only once 7.
Noticed that std::function have an empty state, we can have the following implementation
template<typename T>
class Maybe{
private:
Maybe(T t){
get = [t](){ return t; };
}
Maybe(){}
std::function<T ()> get;
public:
typedef T content_type;
template<typename WhenJust, typename WhenNothing>
auto on(WhenJust &&whenJust, WhenNothing &&whenNothing)
-> decltype(whenNothing()){
if(get==nullptr) return whenNothing();
else return whenJust(get());
}
template<typename U>
friend Maybe<U> just(U u);
template<typename U>
friend Maybe<U> nothing();
};
template<typename T>
Maybe<T> just(T t){
return Maybe<T>(t);
}
template<typename T>
Maybe<T> nothing(){
return Maybe<T>();
}
template<typename T, typename BinderFunction>
auto operator >>(Maybe<T> m, BinderFunction bind)
-> Maybe<typename decltype(bind(*((T*)nullptr)))::content_type> {
return m.on([bind](T v){
return bind(v);
},[](){
return nothing<typename decltype(bind(*((T*)nullptr)))::content_type>();
});
}
In this implementation, all factory methods are free (friend) functions, the >> operator (not to be confused with >> in Haskell, this is the equivalent of >>= with same associative) is also free, and even not a friend function. Also notice the on member function, this is used to force any client intended to use a Maybe instance must be prepared for both cases (Just or Nothing).
Here is an example of usage:
int main()
{
auto n = just(10) >> [](int j){ std::cout<<j<<" >> "; return just(j+10.5); }
>> [](double d){ std::cout<<d<<" >> "; return nothing<char>(); }
>> [](char c){ std::cout<<c; return just(10); }
;
n.on(
[](int i) { std::cout<<i; },
[]() { std::cout<<"nothing!"; });
std::cout << std::endl;
return 0;
}
The output is
10 >> 20.5 >> nothing!
My 5 cts.
Sample usage:
Maybe<string> m1 ("longlonglong");
auto res1 = m1 | lengthy | length;
lengthy and length are "monadic lambdas", i.e.
auto length = [] (const string & s) -> Maybe<int>{ return Maybe<int> (s.length()); };
Complete code:
// g++ -std=c++1y answer.cpp
#include <iostream>
using namespace std;
// ..................................................
// begin LIBRARY
// ..................................................
template<typename T>
class Maybe {
//
// note: move semantics
// (boxed value is never duplicated)
//
private:
bool is_nothing = false;
public:
T value;
using boxed_type = T;
bool isNothing() const { return is_nothing; }
explicit Maybe () : is_nothing(true) { } // create nothing
//
// naked values
//
explicit Maybe (T && a) : value(std::move(a)), is_nothing(false) { }
explicit Maybe (T & a) : value(std::move(a)), is_nothing(false) { }
//
// boxed values
//
Maybe (Maybe & b) : value(std::move(b.value)), is_nothing(b.is_nothing) { b.is_nothing = true; }
Maybe (Maybe && b) : value(std::move(b.value)), is_nothing(b.is_nothing) { b.is_nothing = true; }
Maybe & operator = (Maybe & b) {
value = std::move(b.value);
(*this).is_nothing = b.is_nothing;
b.is_nothing = true;
return (*this);
}
}; // class
// ..................................................
template<typename IT, typename F>
auto operator | (Maybe<IT> mi, F f) // chaining (better with | to avoid parentheses)
{
// deduce the type of the monad being returned ...
IT aux;
using OutMonadType = decltype( f(aux) );
using OT = typename OutMonadType::boxed_type;
// just to declare a nothing to return
Maybe<OT> nothing;
if (mi.isNothing()) {
return nothing;
}
return f ( mi.value );
} // ()
// ..................................................
template<typename MO>
void showMonad (MO m) {
if ( m.isNothing() ) {
cout << " nothing " << endl;
} else {
cout << " something : ";
cout << m.value << endl;
}
}
// ..................................................
// end LIBRARY
// ..................................................
// ..................................................
int main () {
auto lengthy = [] (const string & s) -> Maybe<string> {
string copyS = s;
if (s.length()>8) {
return Maybe<string> (copyS);
}
return Maybe<string> (); // nothing
};
auto length = [] (const string & s) -> Maybe<int>{ return Maybe<int> (s.length()); };
Maybe<string> m1 ("longlonglong");
Maybe<string> m2 ("short");
auto res1 = m1 | lengthy | length;
auto res2 = m2 | lengthy | length;
showMonad (res1);
showMonad (res2);
} // ()
Literally copy & pasting from Haskell style "Maybe" type & *chaining* in C++11
This is probably what you really want to achieve
#include <iostream>
#include <map>
#include <deque>
#include <algorithm>
#include <type_traits>
typedef long long int int64;
namespace monad { namespace maybe {
struct Nothing {};
template < typename T >
struct Maybe {
template < typename U, typename Enable = void >
struct ValueType {
typedef U * const type;
};
template < typename U >
struct ValueType < U, typename std::enable_if < std::is_reference < U >::value >::type > {
typedef typename std::remove_reference < T >::type * const type;
};
typedef typename ValueType < T >::type value_type;
value_type m_v;
Maybe(Nothing const &) : m_v(0) {}
struct Just {
value_type m_v;
Just() = delete;
explicit Just(T &v) : m_v(&v) {
}
};
Maybe(Just const &just) : m_v(just.m_v) {
}
};
Nothing nothing() {
return Nothing();
}
template < typename T >
Maybe < T > just(T &v) {
return typename Maybe < T >::Just(v);
}
template < typename T >
Maybe < T const > just(T const &v) {
return typename Maybe < T const >::Just(v);
}
template < typename T, typename R, typename A >
Maybe < R > operator | (Maybe < T > const &t, R (*f)(A const &)) {
if (t.m_v)
return just < R >(f(*t.m_v));
else
return nothing();
}
template < typename T, typename R, typename A >
Maybe < R > operator | (Maybe < T > const &t, Maybe < R > (*f)(A const &)) {
if (t.m_v)
return f(*t.m_v);
else
return nothing();
}
template < typename T, typename R, typename A >
Maybe < R > operator | (Maybe < T > const &t, R (*f)(A &)) {
if (t.m_v)
return just < R >(f(*t.m_v));
else
return nothing();
}
template < typename T, typename R, typename A >
Maybe < R > operator | (Maybe < T > const &t, Maybe < R > (*f)(A &)) {
if (t.m_v)
return f(*t.m_v);
else
return nothing();
}
template < typename T, typename R, typename... A >
Maybe < R > operator | (Maybe < T const > const &t, R (T::*f)(A const &...) const) {
if (t.m_v)
return just < R >(((*t.m_v).*f)());
else
return nothing();
}
template < typename T, typename R, typename... A >
Maybe < R > operator | (Maybe < T const > const &t, Maybe < R > (T::*f)(A const &...) const) {
if (t.m_v)
return just < R >((t.m_v->*f)());
else
return nothing();
}
template < typename T, typename R, typename... A >
Maybe < R > operator | (Maybe < T const > const &t, R (T::*f)(A const &...)) {
if (t.m_v)
return just < R >(((*t.m_v).*f)());
else
return nothing();
}
template < typename T, typename R, typename... A >
Maybe < R > operator | (Maybe < T const > const &t, Maybe < R > (T::*f)(A const &...)) {
if (t.m_v)
return just < R >((t.m_v->*f)());
else
return nothing();
}
template < typename T, typename A >
void operator | (Maybe < T > const &t, void (*f)(A const &)) {
if (t.m_v)
f(*t.m_v);
}
}}
struct Account {
std::string const m_id;
enum Type { CHECKING, SAVINGS } m_type;
int64 m_balance;
int64 withdraw(int64 const amt) {
if (m_balance < amt)
m_balance -= amt;
return m_balance;
}
std::string const &getId() const {
return m_id;
}
};
std::ostream &operator << (std::ostream &os, Account const &acct) {
os << "{" << acct.m_id << ", "
<< (acct.m_type == Account::CHECKING ? "Checking" : "Savings")
<< ", " << acct.m_balance << "}";
}
struct Customer {
std::string const m_id;
std::deque < Account > const m_accounts;
};
typedef std::map < std::string, Customer > Customers;
using namespace monad::maybe;
Maybe < Customer const > getCustomer(Customers const &customers, std::string const &id) {
auto customer = customers.find(id);
if (customer == customers.end())
return nothing();
else
return just(customer->second);
};
Maybe < Account const > getAccountByType(Customer const &customer, Account::Type const type) {
auto const &accounts = customer.m_accounts;
auto account = std::find_if(accounts.begin(), accounts.end(), [type](Account const &account) -> bool { return account.m_type == type; });
if (account == accounts.end())
return nothing();
else
return just(*account);
}
Maybe < Account const > getCheckingAccount(Customer const &customer) {
return getAccountByType(customer, Account::CHECKING);
};
Maybe < Account const > getSavingsAccount(Customer const &customer) {
return getAccountByType(customer, Account::SAVINGS);
};
int64 const &getBalance(Account const &acct) {
return acct.m_balance;
}
template < typename T >
void print(T const &v) {
std::cout << v << std::endl;
}
int main(int const argc, char const * const argv[]) {
Customers customers = {
{ "12345", { "12345", { { "12345000", Account::CHECKING, 20000 }, { "12345001", Account::SAVINGS, 117000 } } } }
, { "12346", { "12346", { { "12346000", Account::SAVINGS, 1000000 } } } }
};
getCustomer(customers, "12346") | getCheckingAccount | getBalance | &print < int64 const >;
getCustomer(customers, "12345") | getCheckingAccount | getBalance | &print < int64 const >;
getCustomer(customers, "12345") | getSavingsAccount | &Account::getId | &print < std::string const >;
// getCustomer(customers, "12345") | getSavingsAccount | [](Account &acct){ return acct.withdraw(100); } | &print < std::string const >;
}