'Assignable' Expression Templates?

B

bartek

Hello,

I've been toying around with expression templates recently
while writing a simple static lexical analyser,
hence I have some questions which keep bothering me...
The expression objects are wrapped around following the
'curious base' pattern.

E.g.

//---------------------------
// BASE class for expressions
//---------------------------
template <typename T>
class Base : public T
{
public:
T& Get()
{
return *static_cast<T*>(this);
}
//...const overload here...
};

//---------------------------
// Item that does the work.
//---------------------------
class Item : Base <Item>
{
public:
bool DoIt( /*...*/ ) const
{
// ...
// return true on successful work.
}
};

//---------------------------
// Expression object (OR)
//---------------------------
template <typename T1, typename T2>
class OrExpression : Base < OrExpression<T1, T2> >
{
public:
OrExpresion(T1 const& l, T2 const& r)
: m_l(l), m_r(r)
{ }

bool DoIt( /*...*/ ) const
{
return m_l.DoIt( /*...*/ ) | m_r.DoIt( /*...*/ );
}
private:
T1 m_l;
T2 m_r;
};

template <typename T1, typename T2>
inline OrExpression<T1, T2>
operator|(Base<T1> const& l, Base<T2> const& r)
{
return OrExpression<T1, T2>(l.Get(), r.Get());
}

// etc...

With respective operator overloads, it allows me to write
expressions of Item-like objects:

template <typename T>
void DoSomething(Base<T> const& expr);

Item a, b, c;
DoSomething(a & b | c);

However, I can only use those expressions to generate temporary
objects. If I wanted to assign such an expression to a variable,
I'd have to explicitly specify its type...

My question: Is there a technique on such use of assignable
expression templates?

E.g.
Item a, b, c;
MyExpression e;
e = a & b | c;

Thank you in advance for any hints...
Regards,
bartek
 
G

Gianni Mariani

bartek said:
Hello,

I've been toying around with expression templates recently
while writing a simple static lexical analyser,
hence I have some questions which keep bothering me...
The expression objects are wrapped around following the
'curious base' pattern.
....

However, I can only use those expressions to generate temporary
objects. If I wanted to assign such an expression to a variable,
I'd have to explicitly specify its type...

My question: Is there a technique on such use of assignable
expression templates?

E.g.
Item a, b, c;
MyExpression e;
e = a & b | c;

Thank you in advance for any hints...

You need to have a base expression class and you need to create non
temporary objects with some kind of object lifetime management
(reference counting).

Having a different base type for every type of node will be a problem.

i.e. if you do this:

Item & e = DeepCopy( a & b | c );

You need to know when to delete what e is referencing.

So you'll need some kind of smart pointer.

pointer<Item> e = DeepCopy( a & b | c );

I can provide more details later but suffice to say, you need to use
dynamic objects. The "operator &(...)" call needs to return a reference
to a dynamically allocated object i.e.

Item & operator&( Item & rhs )
{
return * new AndThing( * this, rhs );
}


G
 
B

bartek

You need to have a base expression class and you need to create non
temporary objects with some kind of object lifetime management
(reference counting).

Having a different base type for every type of node will be a problem.

i.e. if you do this:

Item & e = DeepCopy( a & b | c );

You need to know when to delete what e is referencing.

So you'll need some kind of smart pointer.

pointer<Item> e = DeepCopy( a & b | c );

I can provide more details later but suffice to say, you need to use
dynamic objects. The "operator &(...)" call needs to return a reference
to a dynamically allocated object i.e.

Item & operator&( Item & rhs )
{
return * new AndThing( * this, rhs );
}

I thought of using an expression base class with the virtual DoIt method,
and overloaded assignment operator to make up a polymorphic type. Something
like the following (just guessing):

class PolyExpressionBase
{
public:
virtual bool DoIt( /*...*/ ) const = 0;
};

template <typename T>
class PolyExpression : public PolyExpressionBase
{
PolyExpression(T& const expr)
: m_expr(expr)
{ }

bool DoIt( /*...*/ ) const
{
return m_expr.DoIt( /*...*/ );
}

private:
T m_expr;
};

class Expression
{
public:
/* ...ctors, dtor, etc... */

template <typename T>
Expression& operator=(T const& expr)
{
/* ...cruft... */
m_expr = new PolyExpression<T>(expr);
return *this;
}

/* ...cruft... */

private:
PolyExpressionBase* m_expr;
};

It seems it would sort of encapsulate the static structure of an expression
in a dynamic object. However I really would like to keep things as much
static as possible.

Thanks a lot for the hint.
Regards,
bartek
 
A

anon luker

There are many who believe that the auto keyword should be overloaded
to ease your pain (google author:David Abrahams auto proposal). You
might find it worthwhile to look at spirit to see how they do it, too.
Static binding is possible if you're willing to tolerate ugly code.
 
B

bartek

(e-mail address removed) (anon luker) wrote in
There are many who believe that the auto keyword should be overloaded
to ease your pain (google author:David Abrahams auto proposal). You
might find it worthwhile to look at spirit to see how they do it, too.
Static binding is possible if you're willing to tolerate ugly code.

I am aware of the 'auto proposal'. I wouldn't mind it, of course. It
doesn't help me at the moment, though.

I'm looking inside of Spirit at the moment, but it's ... kind of ...
complex... MY goodness!!! Am I going to figure it out someday AT ALL!?
Doh!

Cheers,
bartek
 
G

Gianni Mariani

bartek said:
[email protected]: ....

It seems it would sort of encapsulate the static structure of an expression
in a dynamic object. However I really would like to keep things as much
static as possible.

This is more or less the way I did it a while back and it works just
fine (as long as you reference count it or manage it's life-time some
other way - I used reference counting with a special case where objects
were created with a reference count of 0 - this simplified the code
somewhat).

There really is no other way to make an expression like the one you
showed do this.

I also had a number of other methods to help with optimizations etc.
The expression was a template that was based on a "value type" and the
value type needed to support all the methods for managing themselves.

As for making things as static as possible, yep, it would be nice but it
really does not matter since you never really need to worry about the
performance (at least I didn't).
 
A

anon luker

well... what you're trying to do is hard in nature. Something worth
keeping in mind, though, is that if the compiler can instantiate your
function template for assignment then the resulting type is known at
compile time. Determination of that type is independent of the
semantics of the actual assignment - whether you use a deep copy or a
shallow one, whether you ref count or not, all of those choices are
independent of your ability to properly instantiate an object to hold
the result. The alternative is to kludge and make an inhomogeneous
bag style container - not recommended.
 
B

bartek

(e-mail address removed) (anon luker) wrote in
well... what you're trying to do is hard in nature. Something worth
keeping in mind, though, is that if the compiler can instantiate your
function template for assignment then the resulting type is known at
compile time. Determination of that type is independent of the
semantics of the actual assignment - whether you use a deep copy or a
shallow one, whether you ref count or not, all of those choices are
independent of your ability to properly instantiate an object to hold
the result. The alternative is to kludge and make an inhomogeneous
bag style container - not recommended.

So there's actually no point in doing such a thing. The only benefit would
be making a nice 'sugared up' expression interface using overloaded
operators, but at the expense of having contrived complex dynamic code hell
underneath. I begin wondering, is it really worth the effort?

Cheers,
bartek
 
H

Hendrik Schober

bartek said:
[...]
My question: Is there a technique on such use of assignable
expression templates?

E.g.
Item a, b, c;
MyExpression e;
e = a & b | c;

The only thin I can think of is that, if
you can delegate the task to a function,
you can have the compiler figure it out
for you:

template< typename T >
void f(const T& expr)
{
T e = expr;
// use e
}

void g()
{
// ...
f( a & b | c );
// ...
}

However, 'f()' will be called at run-
time. This is not a compile-time feature.
Thank you in advance for any hints...
Regards,
bartek


Schobi

--
(e-mail address removed) is never read
I'm Schobi at suespammers dot org

"Sometimes compilers are so much more reasonable than people."
Scott Meyers
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,609
Members
45,253
Latest member
BlytheFant

Latest Threads

Top