// { dg-do compile } // { dg-options "-std=c++14 -O2 -ftemplate-depth=1000000" } template struct Tensor3; template struct Tensor3_Expr; template struct Tensor4; template struct Tensor4_Expr; template struct Index {}; template struct Number { Number(){}; operator int() const { return N; } }; template struct Tensor3 { T data[Tensor_Dim0][Tensor_Dim1][Tensor_Dim2]; T operator()(const int N1, const int N2, const int N3) const { return data[N1][N2][N3]; } template Tensor3_Expr, T, Dim0, Dim1, Dim2, i, j, k> operator()(const Index, const Index, const Index) const { return Tensor3_Expr, T, Dim0, Dim1, Dim2, i, j, k>(*this); } }; template struct Tensor3_Expr { A iter; Tensor3_Expr(const A &a) : iter(a) {} T operator()(const int N1, const int N2, const int N3) const { return iter(N1, N2, N3); } }; template struct Tensor3_Expr, T, Dim0, Dim1, Dim2, i, j, k> { Tensor3 &iter; Tensor3_Expr(Tensor3 &a) : iter(a) {} T operator()(const int N1, const int N2, const int N3) const { return iter(N1, N2, N3); } }; template struct Tensor3_times_Tensor3_21 { Tensor3_Expr iterA; Tensor3_Expr iterB; template T eval(const int N1, const int N2, const int N3, const int N4, const Number &) const { return iterA(N1, N2, CurrentDim - 1) * iterB(CurrentDim - 1, N3, N4) + eval(N1, N2, N3, N4, Number()); } T eval(const int N1, const int N2, const int N3, const int N4, const Number<1> &) const { return iterA(N1, N2, 0) * iterB(0, N3, N4); } Tensor3_times_Tensor3_21( const Tensor3_Expr &a, const Tensor3_Expr &b) : iterA(a), iterB(b) {} T operator()(const int &N1, const int &N2, const int &N3, const int &N4) const { return eval(N1, N2, N3, N4, Number()); } }; template Tensor4_Expr, T, Dim0, Dim1, Dim4, Dim5, i, j, l, m> operator*(const Tensor3_Expr &a, const Tensor3_Expr &b) { using TensorExpr = Tensor3_times_Tensor3_21; return Tensor4_Expr( TensorExpr(a, b)); }; template struct Tensor4 { T data[Tensor_Dim0][Tensor_Dim1][Tensor_Dim2][Tensor_Dim3]; Tensor4() {} T &operator()(const int N1, const int N2, const int N3, const int N4) { return data[N1][N2][N3][N4]; } template Tensor4_Expr, T, Dim0, Dim1, Dim2, Dim3, i, j, k, l> operator()(const Index, const Index, const Index, const Index) { return Tensor4_Expr< Tensor4, T, Dim0, Dim1, Dim2, Dim3, i, j, k, l>(*this); }; }; template struct Tensor4_Expr { A iter; Tensor4_Expr(const A &a) : iter(a) {} T operator()(const int N1, const int N2, const int N3, const int N4) const { return iter(N1, N2, N3, N4); } }; template struct Tensor4_Expr, T, Dim0, Dim1, Dim2, Dim3, i, j, k, l> { Tensor4 &iter; Tensor4_Expr(Tensor4 &a) : iter(a) {} T operator()(const int N1, const int N2, const int N3, const int N4) const { return iter(N1, N2, N3, N4); } template auto &operator=(const Tensor4_Expr &rhs) { for(int ii = 0; ii < Dim0; ++ii) for(int jj = 0; jj < Dim1; ++jj) for(int kk = 0; kk < Dim2; ++kk) for(int ll = 0; ll < Dim3; ++ll) { iter(ii, jj, kk, ll) = rhs(ii, jj, kk, ll); } return *this; } }; int main() { Tensor3 t1; Tensor3 t2; Index<'l', 100> l; Index<'m', 100> m; Index<'k', 1000> k; Index<'n', 100> n; Index<'o', 100> o; Tensor4 res; res(l, m, n, o) = t1(l, m, k) * t2(k, n, o); return 0; }