如何编写兼容Eigen Array/Matrix与nullopt的std::optional模板函数
如何修改C++模板函数以支持Eigen对象与std::nullopt混合传参?
原模板函数
template <typename Derived> std::optional<Eigen::Array<typename Derived::Scalar, Eigen::Dynamic, Eigen::Dynamic>> function1(const std::optional<Eigen::ArrayBase<Derived>>& opt1, const std::optional<Eigen::ArrayBase<Derived>>& opt2) { }
需求说明
需要让该模板函数能够接受以下任意组合的参数:
- 两个Eigen Array/Matrix对象
- 一个Eigen对象和一个
std::nullopt - 两个
std::nullopt
例如支持如下调用:
ArrayXXd a(4, 3); ArrayXXd b(4, 3); auto q = function1(a,b); // 直接传Eigen对象 auto r = function1(std::nullopt, b); // 混合传参 auto s = function1(std::nullopt, std::nullopt); // 传nullopt
已知可以编写如下非std::optional版本的模板函数作为参考:
template <typename Derived1, typename Derived2> // 此处省略返回值,根据实际需求定义 function2(const Eigen::ArrayBase<Derived1>& opt1, const Eigen::ArrayBase<Derived2>& opt2) { }
请问如何修改原模板函数以满足需求?
修改方案
方案1:写重载函数(兼容旧版本C++,C++17及以上可用)
最直接的做法是给function1写几个重载,覆盖所有参数组合,同时把核心逻辑抽成内部函数复用:
// 核心实现:专门处理两个Eigen对象的业务逻辑 template <typename Derived1, typename Derived2> std::optional<Eigen::Array<typename Derived1::Scalar, Eigen::Dynamic, Eigen::Dynamic>> function1_impl(const Eigen::ArrayBase<Derived1>& arr1, const Eigen::ArrayBase<Derived2>& arr2) { // 此处编写实际业务代码,例如数组运算、结果返回等 return Eigen::Array<typename Derived1::Scalar, Eigen::Dynamic, Eigen::Dynamic>(arr1.rows(), arr1.cols()); } // 重载1:两个参数都是Eigen对象 template <typename Derived1, typename Derived2> auto function1(const Eigen::ArrayBase<Derived1>& arr1, const Eigen::ArrayBase<Derived2>& arr2) { return function1_impl(arr1, arr2); } // 重载2:第一个是optional,第二个是Eigen对象 template <typename Derived1, typename Derived2> auto function1(const std::optional<Eigen::ArrayBase<Derived1>>& opt1, const Eigen::ArrayBase<Derived2>& arr2) { if (!opt1) return std::nullopt; return function1_impl(*opt1, arr2); } // 重载3:第一个是Eigen对象,第二个是optional template <typename Derived1, typename Derived2> auto function1(const Eigen::ArrayBase<Derived1>& arr1, const std::optional<Eigen::ArrayBase<Derived2>>& opt2) { if (!opt2) return std::nullopt; return function1_impl(arr1, *opt2); } // 重载4:两个参数都是optional template <typename Derived1, typename Derived2> auto function1(const std::optional<Eigen::ArrayBase<Derived1>>& opt1, const std::optional<Eigen::ArrayBase<Derived2>>& opt2) { if (!opt1 || !opt2) return std::nullopt; return function1_impl(*opt1, *opt2); }
方案2:用C20特性简化(现代C推荐)
如果项目基于C++20或以上版本,可以用概念(Concepts)和类型萃取简化代码,自动识别参数类型:
#include <type_traits> // 定义概念:判断类型是否为Eigen ArrayBase的派生类 template <typename T> concept EigenArrayType = std::is_base_of_v<Eigen::ArrayBase<std::decay_t<T>>, std::decay_t<T>>; // 定义概念:判断类型是否为包裹Eigen ArrayBase的optional template <typename T> concept OptionalEigenArrayType = requires(T opt) { typename T::value_type; requires EigenArrayType<typename T::value_type>; *opt; }; // 辅助函数:提取参数值——Eigen对象直接返回,optional先判空再解包 template <EigenArrayType T> const auto& get_value(const T& val) { return val; } template <OptionalEigenArrayType T> const auto& get_value(const T& opt) { if (!opt) throw std::invalid_argument("参数为nullopt"); // 也可根据需求返回std::nullopt,需结合主函数逻辑调整 return *opt; } // 主模板函数:支持Eigen对象或对应optional作为参数 template <typename T1, typename T2> requires (EigenArrayType<T1> || OptionalEigenArrayType<T1>) && (EigenArrayType<T2> || OptionalEigenArrayType<T2>) std::optional<Eigen::Array<typename std::decay_t<T1>::Scalar, Eigen::Dynamic, Eigen::Dynamic>> function1(const T1& arg1, const T2& arg2) { // 检查是否存在nullopt参数 if constexpr (OptionalEigenArrayType<T1> && !arg1) { return std::nullopt; } if constexpr (OptionalEigenArrayType<T2> && !arg2) { return std::nullopt; } // 提取有效值并执行核心逻辑 const auto& arr1 = get_value(arg1); const auto& arr2 = get_value(arg2); // 此处编写业务逻辑 return Eigen::Array<typename decltype(arr1)::Scalar, Eigen::Dynamic, Eigen::Dynamic>(arr1.rows(), arr1.cols()); }
补充说明
- 方案1无需C++20特性,兼容旧编译器,逻辑直白易维护。
- 方案2利用C20概念简化代码,扩展性更强,适合现代C项目。
- 若需直接支持Eigen Matrix对象,可在逻辑中添加
.array()转换,或新增对应概念与重载。
内容的提问来源于stack exchange,提问作者Helloexcel
相关产品推荐
相关产品推荐

