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.
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.