专门针对 Eigen::DenseBase 使用 std::less

问题描述 投票:0回答:2

我需要

Eigen::Matrix
Eigen::Array
的总订单,因此我想将
std::less
专门用于两者的父类:
Eigen::DenseBase
。从 https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html 我知道我必须为模板化类型
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
),要么不返回单个 bool (
Eigen::Array
)。

如何定义小于(<) operator or std::less struct for Eigen::Vector3f?建议不要专门化

std::less
(当使用std::map时),而是显式地提供一个自定义比较结构,这是有效的

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::DenseBase 专门化 std::less 工作?这是一个最小的例子:https://godbolt.org/z/jMdGzf7hT

c++ templates eigen template-specialization
2个回答
0
投票

免责声明:这不是完整的答案,但对于单纯的评论来说太长了。

第一个问题是

less
的特化不在
std
命名空间或嵌入到
std
中的命名空间中,因此不能考虑特化:
来自 cppreferences

此声明必须位于与其专门化的主模板定义相同的命名空间中,或者对于成员模板,类范围。

第二个问题是

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 似乎是允许的:
cpp参考

添加模板专业化
类模板
仅当声明依赖于至少一种程序定义的类型并且专门化满足原始模板的所有要求时,才允许将任何标准库类模板的模板专门化添加到命名空间 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;
}

直播

希望能有所帮助。


0
投票
当尝试编译代码时,

编译器无法理解

Eigen::Array3d
Eigen::DenseBase<Derived>
。当您使用
struct eigenless
时,它没有意义,因为
Eigen::Array3d
可以转换为
Eigen::DenseBase<Derived>
。如果你想使用 spezialized
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());
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.