提问人:j-hap 提问时间:9/27/2023 更新时间:9/28/2023 访问量:97
专门用于 Eigen::D enseBase 的 std::less
Specializing std::less for Eigen::DenseBase
问:
我需要对两者的总顺序,因此我想专门研究两者的父类:。从 https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html 我知道我必须为模板化类型定义。将模板化函数传递到模板函数(特征派生)中包含一个工作示例,因此我将其改编为父类并提出了Eigen::Matrix
Eigen::Array
std::less
Eigen::DenseBase
std::less
Eigen::DenseBase<Derived>
Eigen::Matrix
template <typename Derived>
struct std::less<Eigen::DenseBase<Derived>> {
bool operator()(const Eigen::DenseBase<Derived>& lhs,
const Eigen::DenseBase<Derived>& rhs) const {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
};
这不起作用,因为编译器尝试使用默认值 ,它使用 ,它要么不存在 () 要么不返回单个布尔值 ()。std::less
operator<
Eigen::Matrix
Eigen::Array
如何为 Eigen::Vector3f 定义小于 (<) 运算符或 std::less 结构?建议不要专门化(使用 std::map 时),而是显式地提供自定义比较结构,这有效std::less
struct eigenless {
template <class Derived>
bool operator()(Eigen::DenseBase<Derived> const& lhs,
Eigen::DenseBase<Derived> const& rhs) const {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
};
我的问题是:如何使用 Eigen::D enseBase 进行 std::less 的专业化?下面是一个最小的示例:https://godbolt.org/z/jMdGzf7hT
答:
免责声明:这不是一个完整的答案,但对于单纯的评论来说太长了。
第一个问题是 的专用化不在命名空间或嵌入的命名空间中,因此不能考虑专用化:
来自 cppreferencesless
std
std
此声明必须位于同一命名空间中,或者对于成员模板,该声明必须与它专用的主模板定义位于类范围中。
第二个问题是继承自 但不是 .添加一个专业化使其工作如下,但这不是您想要实现的。Eigen::Array3d
Eigen::DenseBase<Derived>
Eigen::DenseBase<Derived>
Eigen::Array3d
#include <Eigen/Core>
#include <map>
namespace std {
template <class Derived>
struct less<Eigen::DenseBase<Derived>> {
bool operator()(const Eigen::DenseBase<Derived>& lhs,
const Eigen::DenseBase<Derived>& rhs) const {
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
rhs.cbegin(), rhs.cend());
}
};
template <>
struct less<Eigen::Array3d> {
bool operator()(const Eigen::Array3d& lhs,
const Eigen::Array3d& rhs) const {
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
rhs.cbegin(), rhs.cend());
}
};
} // namespace std
// not specializing std::less, but using custom Compare, see
// https://stackoverflow.com/questions/68321552
struct eigenless {
template <class Derived>
bool operator()(Eigen::DenseBase<Derived> const& lhs,
Eigen::DenseBase<Derived> const& rhs) const {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
};
int main() {
Eigen::Array3d a;
Eigen::Array3d b;
auto map1 = std::map<decltype(a), int>();
map1[a] = 1;
map1[b] = 2;
auto map2 = std::map<decltype(a), int, eigenless>();
map2[a] = 1;
map2[b] = 2;
}
在您的情况下,似乎允许使用部分专业化扩展 std:cppreference:
添加模板专用化 类模板 仅当声明依赖于至少一个程序定义的类型并且专用化满足原始模板的所有要求时,才允许将任何标准库类模板的模板
专用化添加到命名空间 std,除非禁止此类专用化
。
顺便说一句,专门研究不相关的命名空间是行不通的。
关于继承问题,我开始认为这是不可能的,至少在不修改主要模板参数的情况下,在这种情况下这是不可能的。
就您而言,您仍然可以专攻(和):Eigen::Array
Eigen::Matrix
#include <Eigen/Core>
#include <map>
namespace std {
template <typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
struct less<Eigen::Array<Scalar, RowsAtCompileTime, ColsAtCompileTime>> {
bool operator()(
const Eigen::Array<Scalar, RowsAtCompileTime, ColsAtCompileTime>& lhs,
const Eigen::Array<Scalar, RowsAtCompileTime, ColsAtCompileTime>& rhs)
const {
return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
rhs.cbegin(), rhs.cend());
}
};
// template <>
// struct less<Eigen::Array3d> {
// bool operator()(const Eigen::Array3d& lhs,
// const Eigen::Array3d& rhs) const {
// return std::lexicographical_compare(lhs.cbegin(), lhs.cend(),
// rhs.cbegin(), rhs.cend());
// }
// };
} // namespace std
// not specializing std::less, but using custom Compare, see
// https://stackoverflow.com/questions/68321552
struct eigenless {
template <class Derived>
bool operator()(Eigen::DenseBase<Derived> const& lhs,
Eigen::DenseBase<Derived> const& rhs) const {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
};
int main() {
Eigen::Array3d a;
Eigen::Array3d b;
auto map1 = std::map<decltype(a), int>();
map1[a] = 1;
map1[b] = 2;
auto map2 = std::map<decltype(a), int, eigenless>();
map2[a] = 1;
map2[b] = 2;
}
[编辑]最终,继承管理可以采用解决方法,而无需修改主模板(在这种情况下是不可能的)。我不觉得它令人满意,但我还是给它,作为记录:
#include <Eigen/Core>
#include <map>
#include <type_traits>
template <typename T>
struct EigenWrapper {
static_assert(std::is_base_of<Eigen::DenseBase<T>, T>::value, "");
using type = T;
T const& val;
EigenWrapper(T const& v) : val(v){};
};
namespace std {
/// works only for 1D data, that have iterators
template <typename T>
struct less<EigenWrapper<T>> {
bool operator()(EigenWrapper<T> const& lhs,
EigenWrapper<T> const& rhs) const {
return std::lexicographical_compare(lhs.val.cbegin(), lhs.val.cend(),
rhs.val.cbegin(), rhs.val.cend());
}
};
} // namespace std
int main() {
Eigen::Array3d a;
Eigen::Array3d b;
auto map1 = std::map<decltype(EigenWrapper(a)), int>();
map1[EigenWrapper(a)] = 1;
map1[EigenWrapper(b)] = 2;
}
Live
在这个代码片段中,我为派生自的所有类创建了一种代理类,并且我部分专用于这些代理。正如你所看到的,仅仅管理数组和一维数据是不够的,因为似乎只有一维数据有一个迭代器接口。但是,您可以保留相同的技术来进一步专业化(专业化现在可以将其实现委托给用户定义的函子,该函子可以根据包装对象的性质进行专业化)。
然而,在这种情况下,它至少与对 和 的专业化一样多。除了客户端代码是
可读性较差,因为它必须与对象而不是普通对象一起使用。如果 C++ 小于 17,情况会更糟,因为无法从构造函数中推导出模板参数。您必须显式它或使用 creator 函数来进行参数推导。
尽管如此,我发现该技术值得一提,因为它可以应用于另一个类层次结构。Eigen::DenseBase
std::less
Eigen
std::less
EigenWrapper
Eigen::Array
Eigen::Matrix
EigenWrapper
EigenWrapper
希望它会有所帮助。
评论
struct std::less
namespace std { struct less ...
std::
namespace std {
namespace std
std::less
std::less
编译器不明白这是尝试编译代码的时候。当你使用它时,它没有意义,因为可以转换为.如果你想使用 spezialized ,你可以使用这样的东西Eigen::Array3d
Eigen::DenseBase<Derived>
struct eigenless
Eigen::Array3d
Eigen::DenseBase<Derived>
std::less
template<>
template<typename _Scalar, int d>
struct std::less<Eigen::Array<_Scalar, d, 1>> {
bool operator()(const Eigen::Array<_Scalar, d, 1>& lhs,
const Eigen::Array<_Scalar, d, 1>& rhs) const {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
};
评论
less
operator[]
std