fork download
  1. #include <cassert>
  2. #include <iostream>
  3.  
  4. namespace expr
  5. {
  6. typedef unsigned int uint;
  7.  
  8. // globals to count constructor and destructor calls
  9. // of a vec
  10. uint ctor_calls = 0;
  11. uint dtor_calls = 0;
  12. // print the numbers
  13. void printctor()
  14. {
  15. std::cout << "ctor/dtor = " << ctor_calls
  16. << "/" << dtor_calls << "\n";
  17. }
  18.  
  19. // an example vec container of three successive floats
  20. class vec
  21. {
  22. public:
  23.  
  24. float v[3];
  25.  
  26. // note: the {...} is c++0x initializer syntax
  27. vec () : v({0,0,0}) { ++ctor_calls; }
  28. vec (const vec& o) : v({o.v[0], o.v[1], o.v[2]}) { ++ctor_calls; }
  29. vec (float x,float y,float z) : v({x,y,z}) { ++ctor_calls; }
  30.  
  31. ~vec() { ++dtor_calls; }
  32.  
  33. // return indexed value
  34. float operator[](uint index) const { return v[index]; }
  35. // return indexed reference
  36. float& operator[](uint index) { return v[index]; }
  37.  
  38. void print() { std::cout << "<"<<v[0]<<","<<v[1]<<","<<v[2]<<">\n"; }
  39.  
  40. // assignment to an expression
  41. // E must have operator[](uint)
  42. template <class E>
  43. vec& operator= (const E& x)
  44. {
  45. for (uint i=0; i!=3; ++i) (*this)[i] = x[i];
  46. return *this;
  47. }
  48. };
  49.  
  50.  
  51. // basic catch-all expression node
  52. // L and R must provide operator[](uint)
  53. // O must provide static function float eval(float,float)
  54. template <class L, class O, class R>
  55. struct expression
  56. {
  57. expression(const L& l, const R& r)
  58. : l(l), r(r) { }
  59.  
  60. float operator[](const uint index) const
  61. {
  62. return O::eval(l[index], r[index]);
  63. }
  64.  
  65. const L& l;
  66. const R& r;
  67. };
  68.  
  69. // wraps a reference to float into an operator[](uint) entity
  70. class scalar
  71. {
  72. public:
  73.  
  74. scalar(const float& t) : t(t) { }
  75.  
  76. // act like an endless vector of ts
  77. float operator[](uint) const { return t; }
  78.  
  79. const float& t;
  80. };
  81.  
  82. // an operation function object
  83. struct plus
  84. {
  85. static float eval(const float a, const float b) { return a + b; }
  86. };
  87.  
  88. // anything + anything
  89. template <class L, class R>
  90. expression<L,plus,R> operator+(const L& l, const R& r)
  91. {
  92. return expression<L,plus,R>(l, r);
  93. }
  94.  
  95. // anything + scalar
  96. template <class L>
  97. expression<L,plus,scalar> operator+(const L& l, const float& r)
  98. {
  99. return expression<L,plus,scalar>(l, r);
  100. }
  101. }
  102.  
  103. void do_some()
  104. {
  105. using namespace expr;
  106.  
  107. vec a(1,2,3), b(2,3,4), c(3,4,5);
  108. a.print(); b.print(); c.print();
  109.  
  110. // works
  111. a = b + c;
  112. a.print();
  113. assert( a.v[0] == 5 && a.v[1] == 7 && a.v[2] == 9 );
  114.  
  115. // does not work -> segfault
  116. a = b + 1.f;
  117. a.print();
  118. assert( a.v[0] == 3 && a.v[1] == 4 && a.v[2] == 5 );
  119. }
  120.  
  121. int main()
  122. {
  123. do_some();
  124.  
  125. // check ctor calls
  126. expr::printctor();
  127.  
  128. return 0;
  129. }
Success #stdin #stdout 0s 2884KB
stdin
Standard input is empty
stdout
<1,2,3>
<2,3,4>
<3,4,5>
<5,7,9>
<3,4,5>
ctor/dtor = 3/3