Question

I'm trying to write an expression template and I've run into a problem I don't know how to solve. I've read C++ Templates: The Complete Guide but they don't seem to address this question.

As an example, consider a expression template for a set type set (of integers) with the standard set operations intersection, union, negation, xor, difference, etc. These functions all have efficient implementations in terms of iterators, so I want my expression template classes to have an iterator-like interface. For example,

class set_expr_set
{
  set::iter i;

  set_expr_set (const set &s) : i(s) { }

  operator bool () const { return (bool)i; }
  void operator ++ () { i ++; }
  int val () { return *i; }  
}

and then I have expression template classes set_expr_union, etc. Now, the problem is, the objects created corresponding to expression templates expression are all temporaries and therefore const, but to evaluate the expression I need to iterate through the values (calling ++ and val), and these are non-const. I can't declare set::operator = (set_expr &) as non-const, because the temporaries won't bind a non-const parameter. I could cast away the const-ness in operator =, but that doesn't feel like the right solution.

I'm my example doesn't have enough details to make the problem clear, I'll be happy to clarify.

EDIT: Here are some more details. Suppose set_expr_union and set_expr_intersection have the above interface, too: operator ++, val and operator bool. Also, suppose I have

template<class T>
class set_expr
{
  T t;
  ...;
}

where T is intended to be one of set_expr_union, etc. and set_expr also exports t's ++, val, bool interface.

The expression template objects arise through various operators, e.g.:

template<class T1, class T2>
set_expr<set_expr_intersection>
operator & (const set_expr<T1> &e1, const set_expr<T2> &e2)
{
  return set_expr<set_expr_intersection> (set_expr_intersection (e1.t, e2.t));
}

Really, the temporary corresponding to the return value from the operators is where the problem lies.

Now, consider

class set
{
  ...;

  template<class T>
  set &operator = (const set_expr<T> &e)
  {
    clear ();
    for (; e; e ++)
      add_element (e.val ());
  }
};

which I want to use in something like set3 = set1 & set2.

This is the kind of code I want to write.

Was it helpful?

Solution

One solution is to make your set expressions copy constructable and assignable (which shouldn't be a big problem if they are relatively light-weight, which seems to be the case). In the set assignment operator, you create a copy of the set expression and iterate over the copy.

template<class T>
set& operator=(const set_expr<T> &e) {
  clear ();
  for (set_expr<T> i = e; i; i++) {
    add_element (i.val());
  }
  return *this;
}

If copying the set expressions turns out to be too expensive, consider moving to c++11 and reading up on move semantics.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top