Skip to content

Commit 8ec747c

Browse files
refactor(expression): add function cast_tensor_expression for casting
This function casts any `tensor_expression` to its child class, and it also handles recursive casting to get the real expression that is stored inside the layers of `tensor_expression`.
1 parent d70a701 commit 8ec747c

File tree

5 files changed

+101
-80
lines changed

5 files changed

+101
-80
lines changed

Diff for: include/boost/numeric/ublas/tensor/expression.hpp

+37-32
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@ static constexpr bool does_exp_need_cast_v = does_exp_need_cast< std::decay_t<T>
4343
template<typename E, typename T>
4444
struct does_exp_need_cast< tensor_expression<T,E> > : std::true_type{};
4545

46+
/**
47+
* @brief It is a safer way of casting `tensor_expression` because it handles
48+
* recursive expressions. Otherwise, in most of the cases, we try to access
49+
* `operator()`, which requires a parameter argument, that is not supported
50+
* by the `tensor_expression` class and might give an error if it is not casted
51+
* properly.
52+
*
53+
* @tparam T type of the tensor
54+
* @tparam E type of the child stored inside tensor_expression
55+
* @param e tensor_expression that needs to be casted
56+
* @return child of tensor_expression that is not tensor_expression
57+
*/
58+
template<typename T, typename E>
59+
constexpr auto const& cast_tensor_exression(tensor_expression<T,E> const& e) noexcept{
60+
auto const& res = e();
61+
if constexpr(does_exp_need_cast_v<decltype(res)>)
62+
return cast_tensor_exression(res);
63+
else
64+
return res;
65+
}
66+
67+
68+
// FIXME: remove it when template expression support for the old matrix and vector is removed
69+
/// @brief No Op: Any expression other than `tensor_expression`.
70+
template<typename E>
71+
constexpr auto const& cast_tensor_exression(E const& e) noexcept{ return e; }
72+
4673
template<typename E, typename T>
4774
constexpr auto is_tensor_expression_impl(tensor_expression<T,E> const*) -> std::true_type;
4875

@@ -137,33 +164,15 @@ struct binary_tensor_expression
137164
binary_tensor_expression(const binary_tensor_expression& l) = delete;
138165
binary_tensor_expression& operator=(binary_tensor_expression const& l) noexcept = delete;
139166

167+
constexpr auto const& left_expr() const noexcept{ return cast_tensor_exression(el); }
168+
constexpr auto const& right_expr() const noexcept{ return cast_tensor_exression(er); }
140169

141170
[[nodiscard]] inline
142-
constexpr decltype(auto) operator()(size_type i) const
143-
requires (does_exp_need_cast_v<expression_type_left> && does_exp_need_cast_v<expression_type_right>)
144-
{
145-
return op(el()(i), er()(i));
146-
}
147-
148-
[[nodiscard]] inline
149-
constexpr decltype(auto) operator()(size_type i) const
150-
requires (does_exp_need_cast_v<expression_type_left> && !does_exp_need_cast_v<expression_type_right>)
151-
{
152-
return op(el()(i), er(i));
153-
}
154-
155-
[[nodiscard]] inline
156-
constexpr decltype(auto) operator()(size_type i) const
157-
requires (!does_exp_need_cast_v<expression_type_left> && does_exp_need_cast_v<expression_type_right>)
158-
{
159-
return op(el(i), er()(i));
160-
}
161-
162-
[[nodiscard]] inline
163-
constexpr decltype(auto) operator()(size_type i) const {
164-
return op(el(i), er(i));
171+
constexpr decltype(auto) operator()(size_type i) const {
172+
return op(left_expr()(i), right_expr()(i));
165173
}
166174

175+
private:
167176
expression_type_left el;
168177
expression_type_right er;
169178
binary_operation op;
@@ -211,19 +220,15 @@ struct unary_tensor_expression
211220
constexpr unary_tensor_expression() = delete;
212221
unary_tensor_expression(unary_tensor_expression const& l) = delete;
213222
unary_tensor_expression& operator=(unary_tensor_expression const& l) noexcept = delete;
214-
215-
[[nodiscard]] inline constexpr
216-
decltype(auto) operator()(size_type i) const
217-
requires does_exp_need_cast_v<expression_type>
218-
{
219-
return op(e()(i));
220-
}
223+
224+
constexpr auto const& expr() const noexcept{ return cast_tensor_exression(e); }
221225

222226
[[nodiscard]] inline constexpr
223-
decltype(auto) operator()(size_type i) const {
224-
return op(e(i));
227+
decltype(auto) operator()(size_type i) const {
228+
return op(expr()(i));
225229
}
226230

231+
private:
227232
expression_type e;
228233
unary_operation op;
229234
};

Diff for: include/boost/numeric/ublas/tensor/expression_evaluation.hpp

+33-17
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,20 @@ constexpr auto& retrieve_extents(binary_tensor_expression<T,EL,ER,OP> const& exp
134134
static_assert(has_tensor_types_v<T,binary_tensor_expression<T,EL,ER,OP>>,
135135
"Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors.");
136136

137+
auto const& lexpr = expr.left_expr();
138+
auto const& rexpr = expr.right_expr();
139+
137140
if constexpr ( same_exp<T,EL> )
138-
return expr.el.extents();
141+
return lexpr.extents();
139142

140143
else if constexpr ( same_exp<T,ER> )
141-
return expr.er.extents();
144+
return rexpr.extents();
142145

143146
else if constexpr ( has_tensor_types_v<T,EL> )
144-
return retrieve_extents(expr.el);
147+
return retrieve_extents(lexpr);
145148

146149
else if constexpr ( has_tensor_types_v<T,ER> )
147-
return retrieve_extents(expr.er);
150+
return retrieve_extents(rexpr);
148151
}
149152

150153
#ifdef _MSC_VER
@@ -164,12 +167,14 @@ constexpr auto& retrieve_extents(unary_tensor_expression<T,E,OP> const& expr)
164167

165168
static_assert(has_tensor_types_v<T,unary_tensor_expression<T,E,OP>>,
166169
"Error in boost::numeric::ublas::detail::retrieve_extents: Expression to evaluate should contain tensors.");
170+
171+
auto const& uexpr = expr.expr();
167172

168173
if constexpr ( same_exp<T,E> )
169-
return expr.e.extents();
174+
return uexpr.extents();
170175

171176
else if constexpr ( has_tensor_types_v<T,E> )
172-
return retrieve_extents(expr.e);
177+
return retrieve_extents(uexpr);
173178
}
174179

175180
} // namespace boost::numeric::ublas::detail
@@ -221,20 +226,23 @@ constexpr auto all_extents_equal(binary_tensor_expression<T,EL,ER,OP> const& exp
221226
using ::operator==;
222227
using ::operator!=;
223228

229+
auto const& lexpr = expr.left_expr();
230+
auto const& rexpr = expr.right_expr();
231+
224232
if constexpr ( same_exp<T,EL> )
225-
if(e != expr.el.extents())
233+
if(e != lexpr.extents())
226234
return false;
227235

228236
if constexpr ( same_exp<T,ER> )
229-
if(e != expr.er.extents())
237+
if(e != rexpr.extents())
230238
return false;
231239

232240
if constexpr ( has_tensor_types_v<T,EL> )
233-
if(!all_extents_equal(expr.el, e))
241+
if(!all_extents_equal(lexpr, e))
234242
return false;
235243

236244
if constexpr ( has_tensor_types_v<T,ER> )
237-
if(!all_extents_equal(expr.er, e))
245+
if(!all_extents_equal(rexpr, e))
238246
return false;
239247

240248
return true;
@@ -250,12 +258,14 @@ constexpr auto all_extents_equal(unary_tensor_expression<T,E,OP> const& expr, ex
250258

251259
using ::operator==;
252260

261+
auto const& uexpr = expr.expr();
262+
253263
if constexpr ( same_exp<T,E> )
254-
if(e != expr.e.extents())
264+
if(e != uexpr.extents())
255265
return false;
256266

257267
if constexpr ( has_tensor_types_v<T,E> )
258-
if(!all_extents_equal(expr.e, e))
268+
if(!all_extents_equal(uexpr, e))
259269
return false;
260270

261271
return true;
@@ -281,9 +291,11 @@ inline void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type>
281291
if(!all_extents_equal(expr, lhs.extents() ))
282292
throw std::runtime_error("Error in boost::numeric::ublas::tensor_core: expression contains tensors with different shapes.");
283293

284-
#pragma omp parallel for
294+
auto const& rhs = cast_tensor_exression(expr);
295+
296+
#pragma omp parallel for
285297
for(auto i = 0u; i < lhs.size(); ++i)
286-
lhs(i) = expr()(i);
298+
lhs(i) = rhs(i);
287299
}
288300

289301
/** @brief Evaluates expression for a tensor_core
@@ -310,9 +322,11 @@ inline void eval(tensor_type& lhs, tensor_expression<other_tensor_type, derived_
310322
throw std::runtime_error("Error in boost::numeric::ublas::tensor_core: expression contains tensors with different shapes.");
311323
}
312324

325+
auto const& rhs = cast_tensor_exression(expr);
326+
313327
#pragma omp parallel for
314328
for(auto i = 0u; i < lhs.size(); ++i)
315-
lhs(i) = expr()(i);
329+
lhs(i) = rhs(i);
316330
}
317331

318332
/** @brief Evaluates expression for a tensor_core
@@ -330,9 +344,11 @@ inline void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type>
330344
if(!all_extents_equal( expr, lhs.extents() ))
331345
throw std::runtime_error("Error in boost::numeric::ublas::tensor_core: expression contains tensors with different shapes.");
332346

347+
auto const& rhs = cast_tensor_exression(expr);
348+
333349
#pragma omp parallel for
334350
for(auto i = 0u; i < lhs.size(); ++i)
335-
fn(lhs(i), expr()(i));
351+
fn(lhs(i), rhs(i));
336352
}
337353

338354

@@ -347,7 +363,7 @@ inline void eval(tensor_type& lhs, tensor_expression<tensor_type, derived_type>
347363
template<class tensor_type, class unary_fn>
348364
inline void eval(tensor_type& lhs, unary_fn const& fn)
349365
{
350-
#pragma omp parallel for
366+
#pragma omp parallel for
351367
for(auto i = 0u; i < lhs.size(); ++i)
352368
fn(lhs(i));
353369
}

Diff for: include/boost/numeric/ublas/tensor/multiplication.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ void mtv(SizeType const m,
389389
template <class PointerOut, class PointerIn1, class PointerIn2, class SizeType>
390390
void mtm(PointerOut c, SizeType const*const nc, SizeType const*const wc,
391391
PointerIn1 a, SizeType const*const na, SizeType const*const wa,
392-
PointerIn2 b, SizeType const*const nb, SizeType const*const wb)
392+
PointerIn2 b, [[maybe_unused]] SizeType const*const nb, SizeType const*const wb)
393393
{
394394

395395
// C(i,j) = A(i,k) * B(k,j)

Diff for: test/tensor/tensor/test_tensor_binary_expression.cpp

+24-24
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic,
4646
auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_t>( t, uplus1 );
4747
auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_t>( t, uplus2 );
4848

49-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) );
50-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) );
49+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.expr()) >, tensor_t > ) );
50+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.expr()) >, tensor_t > ) );
5151

5252
for(auto i = 0ul; i < t.size(); ++i){
5353
BOOST_CHECK_EQUAL( uexpr1(i), uplus1(t(i)) );
@@ -59,8 +59,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic,
5959

6060
auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_t>( uexpr1, uexpr2, bplus );
6161

62-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) );
63-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) );
62+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.left_expr().expr()) >, tensor_t > ) );
63+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.right_expr().expr()) >, tensor_t > ) );
6464

6565

6666
for(auto i = 0ul; i < t.size(); ++i){
@@ -69,10 +69,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic,
6969

7070
auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_t>( bexpr_uexpr, t, bminus );
7171

72-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) );
73-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) );
74-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) );
75-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) );
72+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.left_expr().left_expr().expr()) >, tensor_t > ) );
73+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.left_expr().right_expr().expr()) >, tensor_t > ) );
74+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.right_expr()) >, tensor_t > ) );
75+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.right_expr()) >, tensor_t > ) );
7676

7777
for(auto i = 0ul; i < t.size(); ++i){
7878
BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) );
@@ -113,8 +113,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank,
113113
auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_t>( t, uplus1 );
114114
auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_t>( t, uplus2 );
115115

116-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) );
117-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) );
116+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.expr()) >, tensor_t > ) );
117+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.expr()) >, tensor_t > ) );
118118

119119
for(auto i = 0ul; i < t.size(); ++i){
120120
BOOST_CHECK_EQUAL( uexpr1(i), uplus1(t(i)) );
@@ -126,8 +126,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank,
126126

127127
auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_t>( uexpr1, uexpr2, bplus );
128128

129-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) );
130-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) );
129+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.left_expr().expr()) >, tensor_t > ) );
130+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.right_expr().expr()) >, tensor_t > ) );
131131

132132

133133
for(auto i = 0ul; i < t.size(); ++i){
@@ -136,10 +136,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank,
136136

137137
auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_t>( bexpr_uexpr, t, bminus );
138138

139-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) );
140-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) );
141-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) );
142-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) );
139+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.left_expr().left_expr().expr()) >, tensor_t > ) );
140+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.left_expr().right_expr().expr()) >, tensor_t > ) );
141+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.right_expr()) >, tensor_t > ) );
142+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.right_expr()) >, tensor_t > ) );
143143

144144
for(auto i = 0ul; i < t.size(); ++i){
145145
BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) );
@@ -180,8 +180,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static,
180180
auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_t>( t, uplus1 );
181181
auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_t>( t, uplus2 );
182182

183-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_t > ) );
184-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_t > ) );
183+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.expr()) >, tensor_t > ) );
184+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.expr()) >, tensor_t > ) );
185185

186186
for(auto i = 0ul; i < t.size(); ++i){
187187
BOOST_CHECK_EQUAL( uexpr1(i), uplus1(t(i)) );
@@ -193,8 +193,8 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static,
193193

194194
auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_t>( uexpr1, uexpr2, bplus );
195195

196-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_t > ) );
197-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_t > ) );
196+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.left_expr().expr()) >, tensor_t > ) );
197+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.right_expr().expr()) >, tensor_t > ) );
198198

199199

200200
for(auto i = 0ul; i < t.size(); ++i){
@@ -203,10 +203,10 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static,
203203

204204
auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_t>( bexpr_uexpr, t, bminus );
205205

206-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_t > ) );
207-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_t > ) );
208-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) );
209-
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_t > ) );
206+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.left_expr().left_expr().expr()) >, tensor_t > ) );
207+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.left_expr().right_expr().expr()) >, tensor_t > ) );
208+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.right_expr()) >, tensor_t > ) );
209+
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.right_expr()) >, tensor_t > ) );
210210

211211
for(auto i = 0ul; i < t.size(); ++i){
212212
BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) );

Diff for: test/tensor/tensor/test_tensor_unary_expression.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_dynamic,
5252
BOOST_CHECK_EQUAL( uexpr_uexpr(i), uplus1(uplus1(t(i))) );
5353
}
5454

55-
const auto & uexpr_e = uexpr.e;
55+
const auto & uexpr_e = uexpr.expr();
5656

5757
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, tensor_t > ) );
5858

59-
const auto & uexpr_uexpr_e_e = uexpr_uexpr.e.e;
59+
const auto & uexpr_uexpr_e_e = uexpr_uexpr.expr().expr();
6060

6161
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, tensor_t > ) );
6262
}
@@ -101,11 +101,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static_rank,
101101
BOOST_CHECK_EQUAL( uexpr_uexpr(i), uplus1(uplus1(t(i))) );
102102
}
103103

104-
const auto & uexpr_e = uexpr.e;
104+
const auto & uexpr_e = uexpr.expr();
105105

106106
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, tensor_t > ) );
107107

108-
const auto & uexpr_uexpr_e_e = uexpr_uexpr.e.e;
108+
const auto & uexpr_uexpr_e_e = uexpr_uexpr.expr().expr();
109109

110110
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, tensor_t > ) );
111111
}
@@ -150,11 +150,11 @@ BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_static,
150150
BOOST_CHECK_EQUAL( uexpr_uexpr(i), uplus1(uplus1(t(i))) );
151151
}
152152

153-
const auto & uexpr_e = uexpr.e;
153+
const auto & uexpr_e = uexpr.expr();
154154

155155
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, tensor_t > ) );
156156

157-
const auto & uexpr_uexpr_e_e = uexpr_uexpr.e.e;
157+
const auto & uexpr_uexpr_e_e = uexpr_uexpr.expr().expr();
158158

159159
BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, tensor_t > ) );
160160
}

0 commit comments

Comments
 (0)