From 6dbcfc8c8d961a91ecc2666424788ba640872485 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 23 Jan 2024 08:47:14 -0700 Subject: [PATCH] Fix type confusion in Tensor initialization. --- include/deal.II/base/tensor.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/include/deal.II/base/tensor.h b/include/deal.II/base/tensor.h index bc75a71ab0..85a07e8e18 100644 --- a/include/deal.II/base/tensor.h +++ b/include/deal.II/base/tensor.h @@ -1313,7 +1313,27 @@ template constexpr DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor::Tensor(const ArrayLike &initializer, std::index_sequence) - : values{{value_type(initializer[indices])...}} + // Extract from the 'initializer' a sequence of elements via template + // pack evaluation. This could be as easy as + // values{{ (initializer[indices])... }} + // but of course in practice it is not. The challenge is that if rank>1, + // we want to pass the elements initializer[indices] down to the next + // lower rank tensor for evaluation unchanged. But at the rank==1 level, + // we need to convert to the scalar type 'Number'. This would all be + // relatively straightforward if we could rely on automatic type + // conversion, but for some autodifferentiation types, the conversion + // from the AD to double (i.e., the extraction of a scalar value) is + // not implicit, and we need to call internal::NumberType::value() -- + // but as mentioned, we can only do that for rank==1. + // + // We can achieve all of this by dispatching to a lambda function within + // which we can use a 'if constexpr'. + : values{{([&initializer]() -> value_type { + if constexpr (rank_ == 1) + return internal::NumberType::value(initializer[indices]); + else + return value_type(initializer[indices]); + }())...}} { static_assert(sizeof...(indices) == dim, "dim should match the number of indices"); -- 2.39.5