I want to define a class, called Nested
here, that will contains two or more (one here) data members that support arithmetic operations using expression templates, for example an std::valarray
. For this class itself, I am defining its own expression templates and I want to "forward" the arithmetic operations down to the members.
A minimal (non)working example is given below:
#include <iostream>
#include <valarray>
template <typename E>
struct NestedExpr {
operator const E& () const {
return *static_cast<const E*>(this);
}
};
template <typename A>
class Nested : public NestedExpr <Nested<A>>{
private:
A a;
public:
Nested(const A& _a) : a(_a) {}
template <typename E>
inline Nested<A>& operator = (const NestedExpr<E>& _expr) {
const E& expr(_expr);
a = expr.get_a();
return *this;
}
inline A& get_a() { return a; }
inline const A& get_a() const { return a; }
};
// ================================================================= //
template <typename ARG, typename S>
class NestedMul : public NestedExpr<NestedMul<ARG, S>> {
public:
const ARG& arg;
const S s;
NestedMul(const ARG& _arg, S _s) : arg(_arg), s(_s) {}
inline auto get_a() const { return arg.get_a() * s; };
};
template< typename ARG, typename S>
inline NestedMul<ARG, S> operator * (S s, const NestedExpr<ARG>& arg) {
return {arg, s};
}
// ================================================================= //
template <typename ARG1, typename ARG2>
class NestedAdd : public NestedExpr<NestedAdd<ARG1, ARG2>> {
public:
const ARG1& arg1;
const ARG2& arg2;
NestedAdd(const ARG1& _arg1, const ARG2& _arg2)
: arg1(_arg1), arg2(_arg2) {}
inline auto get_a() const { return arg1.get_a() + arg2.get_a(); };
};
template<typename ARG1, typename ARG2>
inline NestedAdd<ARG1, ARG2>
operator + (const NestedExpr<ARG1>& arg1, const NestedExpr<ARG2>& arg2) {
return {arg1, arg2};
}
int main () {
std::valarray<double> x1 = {4.0};
std::valarray<double> x2 = {3.0};
std::valarray<double> x3 = {0.0};
std::valarray<double> x4 = {0.0};
auto a = Nested<std::valarray<double>>(x1);
auto b = Nested<std::valarray<double>>(x2);
auto c = Nested<std::valarray<double>>(x3);
// this returns 21
c = 2*a + 3*b;
std::cout << c.get_a()[0] << std::endl;
// works as expected, returns 17
x4 = 2*x1 + 3*x2;
std::cout << x4[0] << std::endl;
}
The output of this program is
21
17
i.e. forwarding the expression down to the member does not seem to provide the expected result obtained directly from using the valarrays.
Any help here is appreciated.