Related
I am trying to wrap my head around expression templates. In the wikipedia article, an example is given, where an expression template VecSum stores const references to its two operands. A Vec is an expression template that wraps an std::vector<double>. I will first pose my question and then give a complete rundown of the example below.
Can I re-use expressions that use const references to temporaries? And if not, how would I implement light-weight, re-useable expression templates?
For three Vecs a, b, and c the expression a+b+c is of type
VecSum<VecSum<Vec, Vec>, Vec>
If I understand correctly, the inner VecSum is a temporary and the outer VecSum stores a const reference to the inner VecSum. I believe the lifetime of the inner VecSum temporary is guaranteed until the expression a+b+c gets evaluated. Correct? Does this mean that the expression cannot be reused without the danger of creating dangling references?
auto expr = a + b + c;
Vec v1 = expr; // ok
Vec v2 = expr; // not ok!
If so, how can this example be modified, so that
the expressions are reusable
the expressions do not store copies of their operands (at least in situations where it is not necessary)?
Full code example
For completeness - and in case the wikipedia article is updated in the meantime, let me repeat the example code here and give an example in the main that I believe creates a dangling reference.
#include <cassert>
#include <vector>
template <typename E>
class VecExpression {
public:
double operator[](size_t i) const
{
// Delegation to the actual expression type. This avoids dynamic polymorphism (a.k.a. virtual functions in C++)
return static_cast<E const&>(*this)[i];
}
size_t size() const { return static_cast<E const&>(*this).size(); }
};
class Vec : public VecExpression<Vec> {
std::vector<double> elems;
public:
double operator[](size_t i) const { return elems[i]; }
double &operator[](size_t i) { return elems[i]; }
size_t size() const { return elems.size(); }
Vec(size_t n) : elems(n) {}
// construct vector using initializer list
Vec(std::initializer_list<double> init) : elems(init) {}
// A Vec can be constructed from any VecExpression, forcing its evaluation.
template <typename E>
Vec(VecExpression<E> const& expr) : elems(expr.size()) {
for (size_t i = 0; i != expr.size(); ++i) {
elems[i] = expr[i];
}
}
};
template <typename E1, typename E2>
class VecSum : public VecExpression<VecSum<E1, E2> > {
E1 const& _u;
E2 const& _v;
public:
VecSum(E1 const& u, E2 const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
double operator[](size_t i) const { return _u[i] + _v[i]; }
size_t size() const { return _v.size(); }
};
template <typename E1, typename E2>
VecSum<E1, E2>
operator+(VecExpression<E1> const& u, VecExpression<E2> const& v) {
return VecSum<E1, E2>(*static_cast<const E1*>(&u), *static_cast<const E2*>(&v));
}
int main() {
Vec v0 = {23.4,12.5,144.56,90.56};
Vec v1 = {67.12,34.8,90.34,89.30};
Vec v2 = {34.90,111.9,45.12,90.5};
auto expr = v0 + v1 + v2;
Vec v1 = expr; // ok
Vec v2 = expr; // not ok!
}
Edit:
I just realized this might be a duplicate of this question. However the answers to both questions are very different and all usefull.
The comment above has a very effective way to check the problem with the dangling reference. Note that if you try to print the values from the main function in your example the program will still work because the object that will have the dangling reference bound to it will be created also on the stack space of main. I tried to move the code which is assigned to expr inside a function and the program crashed as expected (the temporary object will be in another stack frame):
auto makeExpr1(Vec const& v0, Vec const& v1, Vec const& v2) {
return v0 + v1 + v2;
}
// ... in main:
auto expr = makeExpr1(v0, v1, v2);
The problem you highlighted here appears in the cases of creating an expression that can be lazily evaluated in languages like C++. A somehow similar situation can occur in the context of range expressions (C++20 ranges).
Below is my quick attempt to fix that code and make it work with lvalues and rvalues added with the operator + (I apologise for the ugly parts and possible mistakes). This will store copy of their operands only when they are going to be out of scope and will result in dangling references in the old code.
Regarding re-usability: as long as you define a type for every operation and a corresponding operator '?' function ('?' being the simbol of the operation) this approch should give you a starting point for any binary operation on such a vector.
#include <cassert>
#include <vector>
#include <utility>
#include <iostream>
/*
* Passes lvalues and stores rvalues
*/
template <typename T> class Wrapper;
template <typename T> class Wrapper<T&> {
private:
T& ref;
public:
Wrapper(T& ref) : ref(ref) {}
T& get() { return ref; }
const T& get() const { return ref; }
};
template <typename T> class Wrapper<T&&> {
private:
T value;
public:
Wrapper(T&& ref) : value(std::move(ref)) {}
T& get() { return value; }
const T& get() const { return value; }
};
template <typename E>
class VecExpression {
public:
double operator[](size_t i) const
{
// Delegation to the actual expression type. This avoids dynamic polymorphism (a.k.a. virtual functions in C++)
return static_cast<E const&>(*this)[i];
}
size_t size() const { return static_cast<E const&>(*this).size(); }
};
/*
* Forwards the reference and const qualifiers
* of the expression type to the expression itself
*/
template <typename E> constexpr E& forwardRef(VecExpression<E>& ve) {
return static_cast<E&>(ve);
}
template <typename E> constexpr const E& forwardRef(const VecExpression<E>& ve) {
return static_cast<const E&>(ve);
}
template <typename E> constexpr E&& forwardRef(VecExpression<E>&& ve) {
return static_cast<E&&>(ve);
}
class Vec : public VecExpression<Vec> {
std::vector<double> elems;
public:
double operator[](size_t i) const { return elems[i]; }
double &operator[](size_t i) { return elems[i]; }
size_t size() const { return elems.size(); }
Vec(size_t n) : elems(n) {}
// construct vector using initializer list
Vec(std::initializer_list<double> init) : elems(init) {}
// A Vec can be constructed from any VecExpression, forcing its evaluation.
template <typename E>
Vec(VecExpression<E> const& expr) : elems(expr.size()) {
std::cout << "Expr ctor\n"; // Very quick test
for (size_t i = 0; i != expr.size(); ++i) {
elems[i] = expr[i];
}
}
// Move ctor added for checking
Vec(Vec&& vec) : elems(std::move(vec.elems)) {
std::cout << "Move ctor\n"; // Very quick test
}
};
/*
* Now VecSum is a sum between possibly const - qualified
* and referenced expression types
*/
template <typename E1, typename E2>
class VecSum : public VecExpression<VecSum<E1, E2>> {
Wrapper<E1> _u;
Wrapper<E2> _v;
public:
VecSum(E1 u, E2 v) : _u(static_cast<E1>(u)), _v(static_cast<E2>(v)) {
assert(_u.get().size() == _v.get().size());
}
double operator[](size_t i) const { return _u.get()[i] + _v.get()[i]; }
size_t size() const { return _v.get().size(); }
};
/*
* Used to create a VecSum by capturing also the reference kind
* of the arguments (will be used by the Wrapper inside VecSum)
*/
template <typename E1, typename E2>
auto makeVecSum(E1&& e1, E2&& e2) {
return VecSum<E1&&, E2&&>(std::forward<E1>(e1), std::forward<E2>(e2));
}
/*
* Now the operator+ takes the vector expressions by universal references
*/
template <typename VE1, typename VE2>
auto operator+(VE1&& ve1, VE2&& ve2) {
return makeVecSum(forwardRef(std::forward<VE1>(ve1)), forwardRef(std::forward<VE2>(ve2)));
}
// Now this will work
auto makeExpr1(Vec const& v0, Vec const& v1, Vec const& v2) {
return v0 + v1 + v2;
}
// This will also work - the rvalue is stored in the
// expression itself and both will have the same lifetime
auto makeExpr2(Vec const& v0, Vec const& v1) {
return v0 + v1 + Vec({1.0, 1.0, 1.0, 1.0});
}
int main() {
Vec v0 = {23.4,12.5,144.56,90.56};
Vec v1 = {67.12,34.8,90.34,89.30};
Vec v2 = {34.90,111.9,45.12,90.5};
auto expr = makeExpr1(v0, v1, v2);
Vec v1_ = expr;
Vec v2_ = expr;
auto expr_ = makeExpr2(v0, v1);
for (size_t i = 0; i < v1_.size(); ++i)
std::cout << v1_[i] << " ";
std::cout << std::endl;
for (size_t i = 0; i < v2_.size(); ++i)
std::cout << v2_[i] << " ";
std::cout << std::endl;
for (size_t i = 0; i < expr.size(); ++i)
std::cout << expr[i] << " ";
std::cout << std::endl;
for (size_t i = 0; i < expr_.size(); ++i)
std::cout << expr_[i] << " ";
std::cout << std::endl;
}
I'm working on big codes for which performance matters. And one of the things I read is that raw loops should be avoided and replaced by for_each, range-based for loops, or STL algorithms etc etc. The problem is that in all (most) examples, everything looks adapted for the problem, i.e. for_each is shown with the cout routine *eye roll*.
In my case, the index inside the loop matters (unless you show me otherwise). For example, I want to create tables like this:
std::vector<double> vect1 (nmax), vect2 (nmax);
for (size_t i{0}; i < nmax; ++i) {
vect1[i] = f(i); // f is a routine defined somewhere else
vect2[i] = f(i)+2.0;
}
What I could use is the generate function with a lambda function and it would be something like this:
std::vector<double> vect1 (nmax), vect2 (nmax);
size_t count{0};
generate(vect1.begin(), vect1.end(), [&]() {return f(count++);});
count=0;
generate(vect2.begin(), vect2.end(), [&]() {return f(count++) + 2.0;});
But I’m not a big fan of that, because:
count exists until the end of the routine.
We see that with another function, I have to put back count to zero and generate another vector again. I have to track down all the count variables etc. With the for loop, I could just put it in the same loop.
With the for loop, the correspondence is seen easily. i is on the left and the right. With generate, I feel like it’s counting with a different variable on the left and the right, which means potential mistake.
I can only do count++, not ++count, which means copy of variables.
Of course, this is a simple example. But I would like to know if the generate() version is still better for this kind of things (code/performance/readability wise). Or maybe there’s a better way of doing it, and I’m open to all suggestions and comments.
Thanks!
I wrote an index range that lets me:
std::vector<double> vect1 (nmax), vect2 (nmax);
for (auto i : index_upto(nmax))
vect1[i] = f(i); // f is a routine defined somewhere else
vect2[i] = f(i)+2.0;
}
which eliminates the manual fenceposting but leaves the code otherwise unchanged.
This isn't all that hard. Write a pseudo-iterator that stores a T and returns a copy on unary *. It should support == and ++ (passing both into the stored T).
template<class T>
struct index_it {
T t;
index_it& operator++() { ++t; return *this; }
index_it operator++(int) { auto r = *this; ++*this; return r; }
friend bool operator==( index_it const& lhs, index_it const& rhs ) {
return lhs.t == rhs.t;
}
friend bool operator!=( index_it const& lhs, index_it const& rhs ) {
return lhs.t != rhs.t;
}
T operator*()const& { return t; }
T operator*()&& { return std::move(t); }
};
Next, write a range:
template<class It>
struct range {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
then compose the two.
template<class T>
using index_range = range<index_it<T>>;
template<class T>
index_range<T> make_index_range( T s, T f ) {
return {{std::move(s)}, {std::move(f)}};
}
index_range<std::size_t> index_upto( std::size_t n ) {
return make_index_range( std::size_t(0), n );
}
note that index_it is not an iterator, but works much like one. You could probably finish it and make it an input iterator; beyond that you run into problems as iterators expect backing containers.
Using a stateful lambda is not a good idea. You may be better off writing your own generate function that takes a function object receiving an iterator:
template<class ForwardIt, class Generator>
void generate_iter(ForwardIt first, ForwardIt last, Generator g) {
while (first != last) {
*first = g(first);
++first;
}
}
You can use it as follows:
generate_iter(vect1.begin(), vect1.end(), [&](const std::vector<double>::iterator& iter) {
auto count = std::distance(vect1.begin(), iter);
return f(count);
});
Demo.
We could use a mutable lambda...
#include <vector>
#include <algorithm>
double f(int x) { return x*2; }
int main()
{
constexpr int nmax = 100;
std::vector<double> vect1 (nmax), vect2 (nmax);
std::generate(vect1.begin(),
vect1.end(),
[count = int(0)]() mutable { return f(count++); });
std::generate(vect2.begin(),
vect2.end(),
[count = int(0)]() mutable { return f(count++) + 2.0; });
}
Another option (uses c++17 for template argument deduction):
template<class F>
struct counted_function
{
constexpr counted_function(F f, int start = 0, int step = 1)
: f(f)
, counter(start)
, step(step) {}
decltype(auto) operator()() {
return f(counter++);
}
F f;
int counter;
int step;
};
used as:
std::generate(vect2.begin(),
vect2.end(),
counted_function([](auto x) { return f(x) + 2.0; }));
And finally, just for fun, could write this:
generate(vect2).invoking(f).with(every<int>::from(0).to(nmax - 1));
...if we had written something like this...
#include <vector>
#include <algorithm>
#include <iterator>
double f(int x) { return x*2; }
template<class T> struct value_iter
{
using value_type = T;
using difference_type = T;
using reference = T&;
using pointer = T*;
using iterator_category = std::forward_iterator_tag;
friend bool operator==(value_iter l, value_iter r)
{
return l.current == r.current;
}
friend bool operator!=(value_iter l, value_iter r)
{
return !(l == r);
}
T const& operator*() const& { return current; }
value_iter& operator++() { ++current; return *this; }
T current;
};
template<class T> struct every
{
struct from_thing
{
T from;
struct to_thing
{
auto begin() const { return value_iter<T> { from };}
auto end() const { return value_iter<T> { to+1 };}
T from, to;
};
auto to(T x) { return to_thing { from, x }; }
};
static constexpr auto from(T start)
{
return from_thing { start };
}
};
template<class F>
struct counted_function
{
constexpr counted_function(F f, int start = 0, int step = 1)
: f(f)
, counter(start)
, step(step) {}
decltype(auto) operator()() {
return f(counter++);
}
F f;
int counter;
int step;
};
template <class Container> struct generate
{
generate(Container& c) : c(c) {}
template<class F>
struct invoking_thing
{
template<class Thing>
auto with(Thing thing)
{
using std::begin;
using std::end;
std::copy(begin(thing), end(thing), begin(c));
return c;
}
F f;
Container& c;
};
template<class F>
auto invoking(F f) { return invoking_thing<F>{f, c}; }
Container& c;
};
int main()
{
constexpr int nmax = 100;
std::vector<double> vect2 (nmax);
generate(vect2).invoking(f).with(every<int>::from(0).to(nmax - 1));
}
With range-v3, it would be something like:
auto vect1 = ranges::view::ints(0, nmax) | ranges::view::transform(f);
auto vect2 = ranges::view::ints(0, nmax) | ranges::view::transform(f2);
// or auto vect2 = vect1 | ranges::view::transform([](double d){ return d + 2.; });
Demo
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 >;
}
I don't know if this can even be achivieable, but given these set of functions\class:
float plus1(float x) { return x+1; }
float div2(float x) { return x/2.0f; }
template <typename T>
class chain {
public:
chain(const T& val = T()) : val_(val) {}
chain& operator<<( std::function<float (float)> func ) {
val_ = func(val_);
return *this;
}
operator T() const {
return val_;
}
T val_;
};
I can chain functions operating on floats like this:
float x = chain<float>(3.0f) << div2 << plus1 << div2 << plus1;
However, I'd like to generalize\extend this to being able to convert between types and have functions with arguments. Unfortunately I'm not smart enough to figure out how, or if, this can be done.
Too be more specific I'd like to be able to do something like this (Where operator<< is just an arbitary choice, and preferably I dont even have to write "chain" at the beginning);
Also, these are just dummy examples, I do not intend to use it for arithmetics.
std::string str = chain<float>(3.0) << mul(2.0f) << sqrt << to_string << to_upper;
or
vec3d v = chain<vec3i>(vec3i(1,1,1)) << normalize << to_vec3<double>;
Any ideas?
I think i see why you want to do it. It's similar to the iostream manipulators.
You will always need to start with chain(...) (i.e you will never be able to magically do something like int x = 1 << plus(2) << times(2)), but you can overload the operator int, operator float, ... to allow for the implicit conversions.
You will also need to go back and define each type (like mul) and then implement the operator<< which takes a mul or a const mul, but as a whole it's doable (but a PITA)
A general and extendable solution using boost::proto :
#include <iostream>
#include <boost/proto/proto.hpp>
namespace bp = boost::proto;
// -----------------------------------------------------------------------------
// perform is a callable transform that take a function_ terminal and execute it
// -----------------------------------------------------------------------------
struct perform : bp::callable
{
template<class Sig> struct result;
template<class This, class Func, class In>
struct result<This(Func,In)>
: boost::result_of<typename boost::remove_reference<Func>::type(In)> {};
template<class Func, class In>
typename result<perform(Func &,In)>::type
operator()( Func& f, In& in ) const
{
return f(in);
}
};
// -----------------------------------------------------------------------------
// Grammar for chaining pipe of functions
// -----------------------------------------------------------------------------
struct pipeline_grammar
: bp::or_<
bp::when<
bp::bitwise_or<pipeline_grammar,pipeline_grammar>
, pipeline_grammar(
bp::_right
, pipeline_grammar(bp::_left,bp::_state)
)
>
, bp::when<
bp::terminal<bp::_>
, perform(bp::_value, bp::_state)
>
> {};
// -----------------------------------------------------------------------------
// Forward declaration of the pipeline domain
// -----------------------------------------------------------------------------
struct pipeline_domain;
// -----------------------------------------------------------------------------
// A pipeline is the top level DS entity
// -----------------------------------------------------------------------------
template<class Expr>
struct pipeline : bp::extends<Expr,pipeline<Expr>, pipeline_domain>
{
typedef bp::extends<Expr, pipeline<Expr>, pipeline_domain> base_type;
pipeline(Expr const &expr = Expr()) : base_type(expr) {}
// ---------------------------------------------------------------------------
// A pipeline is an unary callable object
// ---------------------------------------------------------------------------
template<class Input>
typename boost::result_of<pipeline_grammar(pipeline,Input)>::type
operator()(Input const& in) const
{
pipeline_grammar evaluator;
return evaluator(*this,in);
}
};
// -----------------------------------------------------------------------------
// the pipeline_domain make pipeline expression macthes pipeline_grammar
// -----------------------------------------------------------------------------
struct pipeline_domain
: bp::domain<bp::generator<pipeline>,pipeline_grammar>
{};
// -----------------------------------------------------------------------------
// Takes a PFO instance and make it a pipeline terminal
// -----------------------------------------------------------------------------
template<class Func>
typename bp::result_of::
make_expr<bp::tag::terminal, pipeline_domain,Func>::type
task( Func const& f )
{
return bp::make_expr<bp::tag::terminal,pipeline_domain>( f );
}
//--------------------------- Examples --------------------
struct return_value
{
template<class Sig> struct result;
template<class This, class T>
struct result<This(T)> : bp::detail::uncvref<T>
{};
return_value(int i = 1) : factor(i) {}
template<class T>
T operator()(T const& in) const
{
return in*factor;
}
int factor;
};
struct say_hi
{
typedef void result_type;
template<class T>
void operator()(T const& in) const
{
std::cout << "Hi from value = " << in << "\n";
}
};
int main()
{
return_value r1,r2(5);
(task(r1) | task(r2) | task(say_hi())) (7); // SHould print 35
float k = 10,r;
r = (task(r2) | task(r2) | task(r2) | task(r2))(k);
std::cout << r << "\n"; // Should print 6250
}
The basic idea is to wrap function objects as proto terminals, build a small | based grammar and let the proto system deals with the composition.
In order to get conversions between types you would want to have everything return a proxy object, that could convert to any type. Something based on boost::variant, perhaps.
You could also rewrite your operator << as a template function to make it a bit more generic:
template <class UnaryFunction>
chain& operator<<(UnaryFunction func) { _val = func(_val); return *this;}
That would allow you to use any kind of function object as an argument.
To use functions with multiple arguments, you can use the bind function. This was in boost prior to C++11, however now it is in the standard and should be available on any C++11 compatible compiler.
Here is my solution for C++17.
#include <type_traits>
#include <utility>
template <class F>
struct waterfall
{
waterfall(F&& f)
: fn(std::forward<F>(f))
{}
template <class... Args>
decltype(auto) operator()(Args&&... args) const {
return fn(std::forward<Args>(args)...);
}
template <class T>
auto then(T&& t) const & {
return then_impl(fn, std::forward<T>(t));
}
template <class T>
auto then(T&& t) const && {
return then_impl(std::move(fn), std::forward<T>(t));
}
private:
F fn;
template <class In, class Out>
static auto then_impl(In&& in, Out&& out)
{
auto fn = [in = std::forward<In>(in), out = std::forward<Out>(out)](auto&&... args)
{
using InRet = std::invoke_result_t<In, decltype(args)...>;
if constexpr (std::is_invocable_v<Out, InRet>) {
return out(in(std::forward<decltype(args)>(args)...));
}
else {
in(std::forward<decltype(args)>(args)...);
return out();
}
};
return waterfall<decltype(fn)>(std::move(fn));
}
};
And use it like this
int main()
{
// Create a chain
waterfall chain([](const char* s) {
return 42;
})
.then([](auto x) {
// x = 42 here
return x + 1;
})
.then([] {
// Ignoring value from previous function.
// Send double to next one.
return 3.14;
})
.then([](double value) {
// etc...
return true;
});
// chain signature is now bool(const char*)
// Now call our functions in chain
bool ret = chain("test");
}
Suppose we want to apply a series of transformations, int f1(int), int f2(int), int f3(int), to a list of objects. A naive way would be
SourceContainer source;
TempContainer1 temp1;
transform(source.begin(), source.end(), back_inserter(temp1), f1);
TempContainer2 temp2;
transform(temp1.begin(), temp1.end(), back_inserter(temp2), f2);
TargetContainer target;
transform(temp2.begin(), temp2.end(), back_inserter(target), f3);
This first solution is not optimal because of the extra space requirement with temp1 and temp2. So, let's get smarter with this:
int f123(int n) { return f3(f2(f1(n))); }
...
SourceContainer source;
TargetContainer target;
transform(source.begin(), source.end(), back_inserter(target), f123);
This second solution is much better because not only the code is simpler but more importantly there is less space requirement without the intermediate calculations.
However, the composition f123 must be determined at compile time and thus is fixed at run time.
How would I try to do this efficiently if the composition is to be determined at run time? For example, if this code was in a RPC service and the actual composition--which can be any permutation of any subset of f1, f2, and f3--is based on arguments from the RPC call.
EDIT: Working version at http://ideone.com/5GxnW . The version below has the ideas but does not compile. It supports run time type checking, and run time function composition.
The idea is to define a generic (unary) function class, and a way to compose them with run time type checks. This is done with a combination of boost::any, boost::function and the type erasure idiom.
#include <boost/any.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
template <typename T>
struct identity
{
T operator()(const T& x) { return x; }
};
struct any_function
{
template <typename Res, typename Arg>
any_function(boost::function<Res, Arg> f)
{
impl = make_impl(f);
}
boost::any operator()(const boost::any& x)
{
return impl->invoke(x);
}
static any_function compose(const any_function& f,
const any_function& g)
{
any_function ans;
ans.impl = compose_impl(f.impl, g.impl);
return ans;
}
template <typename T>
static any_function id()
{
using boost::function
return any_function(function<T(T)>(identity<T>()));
}
template <typename Res, typename Arg>
boost::function<Res(Arg)> to_function()
{
using boost::function;
return function<Res(Arg)>(to_function_helper(impl));
}
private:
any_function() {}
struct impl_type
{
virtual ~impl_type() {}
virtual boost::any invoke(const boost::any&) = 0;
};
boost::shared_ptr<impl_type> impl;
template <typename Res, typename Arg>
static impl_type* make_impl(boost::function<Res(Arg)> f)
{
using boost::function;
using boost::any;
using boost::any_cast;
class impl : public impl_type
{
function<Res(Arg)> f;
any invoke(const any& x)
{
const Arg& a = any_cast<Arg>(x);
return any(f(a));
}
public:
impl(function<Res(Arg)> f) : f(f) {}
};
return new impl(f);
}
impl_type* compose_impl(boost::shared_ptr<impl_type> f,
boost::shared_ptr<impl_type> g)
{
using boost::any;
using boost::shared_ptr;
class impl : public impl_type
{
shared_ptr<impl> f, g;
any invoke(const any& x)
{
return g->invoke(f->invoke(x));
}
public:
impl(const shared_ptr<impl>& f,
const shared_ptr<impl>& g)
: f(f), g(g)
{}
};
return new impl(f, g);
}
struct to_function_helper
{
template <typename Res, typename Arg>
Res operator()(const Arg& x)
{
using boost::any;
using boost::any_cast;
return any_cast<Res>(p->invoke(any(x)));
}
to_function_helper(const boost::shared_ptr<impl>& p) : p(p) {}
private:
boost::shared_ptr<impl> p;
};
};
Now, let's use standard algorithms and do this (this even works on empty sequences):
// First function passed is evaluated first. Feel free to change.
template <typename Arg, typename Res, typename I>
boost::function<Res(Arg)> pipeline(I begin, I end)
{
return std::accumulate(begin, end,
any_function::id<Arg>,
std::ptr_fun(any_function::compose)
).to_function<Res, Arg>();
}
and use the following to apply it
std::vector<any_function> f;
std::vector<double> v;
std::vector<int> result;
std::transform(v.begin(), v.end(),
result.begin(),
pipeline<double, int>(f.begin(), f.end())
);
You can even use boost::transform_iterator
typedef boost::transform_iterator<
boost::function<double, int>,
std::vector<double>::const_iterator
> iterator;
boost::function<double, int> f = pipeline<double, int>(f.begin(), f.end());
std::copy(iterator(v.begin(), f), iterator(v.end(), f), result.begin());
template<class T>
class compose {
typedef T (*f)(T);
f first_func;
f second_func;
public:
compose(f one,f two) :
first_func(one),
second_func(two)
{}
T operator()(T const &input) {
T temp = first_func(input);
return second_func(temp);
}
};
#ifdef TEST
int f(int x) { return 8 + x; }
int g(int x) { return 2 * x; }
int h(int x) { return x * x; }
#include <iostream>
int main(int argc, char **argv) {
compose<int> x(f, g);
compose<int> y(g, f);
std::cout << x(6) << std::endl;
std::cout << y(6) << std::endl;
typedef int (*func)(int);
func funcs[] = {f, g, h};
compose<int> z(funcs[atoi(argv[1])], funcs[atoi(argv[2])]);
std::cout << z(6);
return 0;
}
#endif
With C++0x, we should be able to use auto to eliminate having to specify the argument/return type. For the moment I've assumed they're the same, though in theory, you might like the ability to include conversions in the mix.
you should use a functor instead of function and pass needed transform functions into functor's constructor
something like
typedef int (*FunctionType)(int);
class Functor
{
FunctionType m_f1;
FunctionType m_f2;
FunctionType m_f3;
public:
Functor(FunctionType f1, FunctionType f2, FunctionType f3):
m_f1(f1), m_f2(f2), m_f3(f3)
{}
int operator()(int n)
{
return (*m_f1)((*m_f2)((*m_f3)(n)));
}
};
// ...
transform(source.begin(), source.end(), back_inserter(temp1), Functor(f1,f2,f3));
if you need variable number of functions then change Functor constructor signature to use vector of functions and fill that vector before calling transform.
Just define an iterator that does what you want:
template<typename T>
struct source
{
virtual source<T>& operator++(void) = 0;
virtual T operator*(void) = 0;
virtual bool atend() = 0;
};
struct source_exhausted
{
};
template<typename T>
bool operator==(const source<T>& comparand, const source_exhausted&)
{ return comparand.atend(); }
template<typename T>
bool operator!=(const source<T>& comparand, const source_exhausted&)
{ return !comparand.atend(); }
template<typename T>
bool operator==(const source_exhausted&, const source<T>& comparand)
{ return comparand.atend(); }
template<typename T>
bool operator!=(const source_exhausted&, const source<T>& comparand)
{ return !comparand.atend(); }
template<typename T, typename iterT, typename endT>
struct source_iterator : source<T>
{
iterT m_iter;
endT m_end;
source_iterator(iterT iter, endT end) : m_iter(iter), m_end(end) {}
virtual source<T>& operator++(void) { ++m_iter; return *this; }
virtual T operator*(void) { return *m_iter; }
virtual bool atend() { return m_iter == m_end; }
};
template<typename T, typename iterT, typename endT>
auto make_source_iterator(iterT iter, endT end) -> source_iterator<decltype(*iter), iterT, endT>
{
return source_iterator<decltype(*iter), iterT, endT>(iter, end);
}
template<typename TContainer>
auto make_source_iterator(TContainer& c) -> source_iterator<typename TContainer::value_type, decltype(c.begin()), decltype(c.end())>
{
return source_iterator<typename TContainer::value_type, decltype(c.begin()), decltype(c.end())>(c.begin(), c.end());
}
template<typename TIn, typename TOut, typename TXform>
struct source_transformer : source<TOut>
{
source<TIn>& m_src;
TXform const m_f;
source_transformer( source<TIn>& src, TXform f ) : m_f(f), m_src(src) {}
virtual source<TOut>& operator++(void) { ++m_src; return *this; }
virtual TOut operator*(void) { return m_f(*m_src); }
virtual bool atend() { return m_src.atend(); }
};
template<typename TIn, typename TOut, typename TXform>
auto make_source_transformer(source<TIn>& src, TXform f) -> source_transformer<TIn, decltype(f(*(TIn*)0)), TXform>
{
return source_transformer<TIn, decltype(f(*(TIn*)0)), TXform>(src, f);
}
typedef int (*f_t)(int);
int f1(int a) { return a + 1; }
int f2(int a) { return a * 2; }
int f3(int a) { return a * a; }
int main()
{
std::vector<f_t> ff = {f1, f2, f3};
std::vector<int> source = {1, 2, 3, 4}, target;
std::transform(source.begin(), source.end(), std::back_inserter(target)
, [&](int a) { for (f_t &f : ff) a = f(a); return a; });
// print target
std::copy(target.begin(), target.end(), std::ostream_iterator<int,char>(std::cout,"\n"));
system("pause");
return 0;
}