vector expression templates, scalars and their scopes

hi there.
trying to implement expression templates for lazy vector evaluation. all seems fine, until i try to operate on single values, like a * 5.
below is a code, stripped from any inlining, additional template parameters and fancy stuff, to point out the problem. used gcc 4.5.2 / c++0x.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <cassert>
#include <iostream>

namespace expr
{
	typedef unsigned int uint;

	// globals to count constructor and destructor calls
	// of a vec
	uint ctor_calls = 0;
	uint dtor_calls = 0;
	// print the numbers
	void printctor()
	{
		std::cout << "ctor/dtor = " << ctor_calls 
                << "/" << dtor_calls << "\n";
	}

	// an example vec container of three successive floats
	class vec
	{
		public:

		float v[3];

		// note: the {...} is c++0x initializer syntax
		vec () : v({0,0,0}) { ++ctor_calls; }
		vec (const vec& o) : v({o.v[0], o.v[1], o.v[2]}) { ++ctor_calls; }
		vec (float x,float y,float z) : v({x,y,z}) { ++ctor_calls; }

		~vec() { ++dtor_calls; }

		// return indexed value
		float operator[](uint index) const { return v[index]; }
		// return indexed reference
		float& operator[](uint index) { return v[index]; }

		void print() { std::cout << "<"<<v[0]<<","<<v[1]<<","<<v[2]<<">\n"; }

		// assignment to an expression
                // E must have operator[](uint)
		template <class E>
		vec& operator= (const E& x)
		{
			for (uint i=0; i!=3; ++i) (*this)[i] = x[i];
			return *this;
		}
	};


	// basic catch-all expression node
	// L and R must provide operator[](uint)
	// O must provide static function float eval(float,float)
	template <class L, class O, class R>
	struct expression
	{
		expression(const L& l, const R& r)
			:	l(l), r(r) { }

		float operator[](const uint index) const
		{
			return O::eval(l[index], r[index]);
		}

		const L& l;
		const R& r;
	};

	// wraps a reference to float into an operator[](uint) entity
	class scalar
	{
		public:

		scalar(const float& t) : t(t) { }

		// act like an endless vector of ts
		float operator[](uint) const { return t; }

		const float& t;
	};

	// an operation function object
	struct plus
	{
		static float eval(const float a, const float b) { return a + b; }
	};

	// anything + anything
	template <class L, class R>
	expression<L,plus,R> operator+(const L& l, const R& r)
	{
		return expression<L,plus,R>(l, r);
	}

	// anything + scalar
	template <class L>
	expression<L,plus,scalar> operator+(const L& l, const float& r)
	{
		return expression<L,plus,scalar>(l, r);
	}
}

void do_some()
{
	using namespace expr;

	vec a(1,2,3), b(2,3,4), c(3,4,5);
	a.print(); b.print(); c.print();

	// works
	a = b + c;
	a.print();
	assert( a.v[0] == 5 && a.v[1] == 7 && a.v[2] == 9 );

	// does not work -> segfault
	a = b + 1.f;
	a.print();
	assert( a.v[0] == 3 && a.v[1] == 4 && a.v[2] == 5 );
}

int main()
{
	do_some();

	// check ctor calls
	expr::printctor();

    return 0;
}


it seems, that the expression object that is created for the scalar by the + operator, does not make it into the execution of operator = of the vec.

if you change the type 't' in 'scalar' from reference to value, you get an uinitialized value. further, typeid(this).name() returns slightly different objects for scalars on the right hand side, where the value is ok and all, and the left hand side, or more precisely, the loop inside vec::operator=.

if you change the type of 'l' and 'r' inside 'expression', the expression objects get copy-constructed and it works. but that turns of lazy evaluation.

it is also possible to create a vector from an expression object on the right-hand-side of an expression, something like
a = make_vec(b + c + 0.5f);
this calls one additional vec constructor and it works.

what is that?
is it the code or the gcc?
i have trouble thinking about the actual scopes of the expression objects..

thanks in advance


Oddly, this works in old gcc 4.1 (without c++11 bits), and works on IDEone http://ideone.com/nS1L0 as is.. but newer gcc and clang++ both segfault in scalar::operator[],

..and I was too slow, but yes, the scalar is an rvalue temporary, which means the destructor is called after the expr<vec, plus, scalar> is constructed and before operator= is called.
Last edited on
hey, thanks for the stats.
i think i found it.
as this article (http://technologyprogram.blogspot.de/2010/11/c-templates-complete-guide-basics_374.html) points out at the bottom of 18.2.1, a scalar value is special, and might not live longer than the right-hand-side of the expression. that kind-of seems logical. so a scalar-expression needs to be held by value, not by reference.

here's the fix for the above code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
struct scalar;

	template <class E>
	struct expression_traits
	{
		// all expressions by const reference
		typedef const E& ref_type;
	};

	template <>
	struct expression_traits< scalar >
	{
		// scalar expressions by value
		typedef scalar ref_type;
	};


	// basic catch-all expression node
	// L and R must provide operator[](uint) (and work with expression_traits<>)
	// O must provide static function float eval(float,float)
	template <class L, class O, class R>
	struct expression
	{
		typedef typename expression_traits<L>::ref_type l_ref;
		typedef typename expression_traits<R>::ref_type r_ref;

		expression(l_ref l, r_ref r) : l(l), r(r) { }

		float operator[](const uint index) const
		{
			return O::eval(l[index], r[index]);
		}

		l_ref l;
		r_ref r;
	};


sorry for the lack of knowledge .. i am not able to understand the program .. can some one tell me that what the program do .

Not able to follow this line
return O::eval(l[index], r[index]);
Last edited on
the code above creates 'compile-time' entities, that (hopefully) wrap an arithmetic expression of e.g.
1
2
// vec = (vec + vec) * scalar
a = (b + c) * 2;

into to a sequence of efficient statements
1
2
3
a[0] = (b[0] + c[0]) * 2;
a[1] = (b[1] + c[1]) * 2;
a[2] = (b[2] + c[2]) * 2;

no temporary of a vector object is needed,
the whole statement (b+c)*2 is processed in one loop.
this holds for any series of statements, as long as each element can be evaluated independently.

in code it's clear i think
1
2
3
4
5
6
7
8
9
10
11
12
expression<vector, plus, scalar > e = vec + 2;
// now e holds the SYNTAX of the above expression, not it's result.

// calculate and print first element
std::cout << e[0] << "\n";

// depending on inlining and optimisation possibilities, the compiler makes something like
std::cout << (vec[0] + 2) << "\n";
// out of the above

// one more
expression<vector, plus, expression<vector, plus, scalar> > e = vec + (vec + 2);


@bluecoder
the O::eval(..) inside expression calls plus::eval. eval is a static function in the struct 'plus', so it can only be
reached through the namespace derefering quadruple thing ::
thanks defgsus .. though it is far beyond my head . .. request all of you to provide with some example/ matarial of this type of program concept to be cleared .
please help.

xxx
@bluecoder just google/wiki/Josuttis "Expression templates". Wiki has an example
thanks Cubbi .. i will
Topic archived. No new replies allowed.