| 208 | template <typename F, typename = std::enable_if_t< |
| 209 | !std::is_same_v<std::decay_t<F>, FunctionExpr>>> |
| 210 | FunctionExpr(const F& f) { |
| 211 | static_assert( |
| 212 | static_cast<int>(F::Differentiability) >= static_cast<int>(TMode), |
| 213 | "Differentiability mode mismatch: source must supply at " |
| 214 | "least as much derivative information as the target mode " |
| 215 | "requires (downgrades are accepted, upgrades are not)."); |
| 216 | static_assert(F::Dimension == TDimension, "Dimension mismatch"); |
| 217 | static_assert(std::is_same<typename F::ScalarType, ScalarType>::value, |
| 218 | "Compile-time scalar-type mismatch"); |
| 219 | if constexpr (F::Differentiability == TMode) { |
| 220 | ptr = f.clone(); |
| 221 | } else { |
| 222 | // Downgrade adapter: wrap the stronger-mode clone so the stored |
| 223 | // pointer type matches `FunctionInterface<TScalar, TMode, Dim>`. |
| 224 | auto source = |
| 225 | f.clone(); // unique_ptr<FunctionInterface<T, F::Mode, Dim>> |
| 226 | ptr = std::make_unique<ModeDowngradeAdapter<TScalar, F::Differentiability, |
| 227 | TMode, TDimension>>( |
| 228 | std::move(source)); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | // Copy constructor. |
| 233 | FunctionExpr(const FunctionExpr& other) |