使用自定义标量类型的Eigen。自定义类型的矩阵乘法失败,"使用重载运算符'*'是不明确的

问题描述 投票:1回答:1

我正在尝试整合 boost.units 变成 Eigenజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ 公文. 我还看了两个项目,它们也做了同样的操作,我也用它们的代码测试了操作,尽管我得到了同样的错误(项目1 项目2).

我所遇到的问题是,当用自定义标量类型的乘法运算符乘以基于 boost::units.

这种行为发生在 clang 10.0.0.3和苹果 clang 11.0.3.

触发错误的代码(use of overloaded operator '*' is ambiguous)是以下内容。

    const Eigen::Matrix<boost::units::quantity<boost::units::si::length, double>, 2, 3> x;
    const Eigen::Matrix<boost::units::quantity<boost::units::si::dimensionless, double>, 3, 1> y;
    const Eigen::Matrix<boost::units::quantity<boost::units::si::length, double>, 2, 1> result = x * y;

为了整合,我创建了包含以下内容的文件 NumTraits 对于 boost::units::quantity<T> 如下所示。

namespace Eigen {

template<class T> struct NumTraits<boost::units::quantity<T>> : NumTraits<double> {
    typedef boost::units::quantity<T> Real;
    typedef boost::units::quantity<T> NonInteger;
    typedef boost::units::quantity<T> Nested;

    enum {
        IsComplex             = 0,
        IsInteger             = 0,
        IsSigned              = 1,
        RequireInitialization = 1,
        ReadCost              = 1,
        AddCost               = 3,
        MulCost               = 3
    };
};
} // namespace Eigen

而对于乘法的支持,我有以下几点: struct 定义。

namespace Eigen {

namespace units = boost::units;

template<typename scalarA, typename scalarB>
struct ScalarBinaryOpTraits<units::quantity<scalarA>, scalarB,
    internal::scalar_product_op<units::quantity<scalarA>, scalarB>> {
    typedef units::quantity<typename units::multiply_typeof_helper<scalarA, scalarB>::type> ReturnType;
};

template<typename scalarA, typename scalarB>
struct ScalarBinaryOpTraits<scalarA, units::quantity<scalarB>,
    internal::scalar_product_op<scalarA, units::quantity<scalarB>>> {
    typedef units::quantity<typename units::multiply_typeof_helper<scalarA, scalarB>::type> ReturnType;
};

template<typename scalarA, typename scalarB>
struct ScalarBinaryOpTraits<scalarA, units::quantity<scalarB>,
    internal::scalar_product_op<units::quantity<scalarA>, units::quantity<scalarB>>> {
    typedef units::quantity<typename units::multiply_typeof_helper<scalarA, scalarB>::type> ReturnType;
};

template<typename scalarA, typename scalarB>
struct ScalarBinaryOpTraits<units::quantity<scalarA>, scalarB,
    internal::scalar_conj_product_op<units::quantity<scalarA>, scalarB>> {
    typedef typename units::multiply_typeof_helper<scalarA, scalarB>::type ReturnType;
};

template<typename scalarA, typename scalarB>
struct ScalarBinaryOpTraits<scalarA, units::quantity<scalarB>,
    internal::scalar_conj_product_op<scalarA, units::quantity<scalarB>>> {
    typedef typename units::multiply_typeof_helper<scalarA, scalarB>::type ReturnType;
};

template<typename scalarA, typename scalarB>
struct ScalarBinaryOpTraits<units::quantity<scalarA>, units::quantity<scalarB>,
    internal::scalar_conj_product_op<units::quantity<scalarA>, units::quantity<scalarB>>> {
    typedef units::quantity<typename units::multiply_typeof_helper<scalarA, scalarB>::type> ReturnType;
};

} // namespace Eigen

完整的错误输出。

Scanning dependencies of target LaserCalibration
[  8%] Building CXX object CMakeFiles/LaserCalibration.dir/maths/Maths.cpp.o
/Users/dwright/projects/dv-laser-calibration/maths/Maths.cpp:9:97: error: use of overloaded operator '*' is ambiguous (with operand types 'const Eigen::Matrix<boost::units::quantity<boost::units::si::length, double>, 2, 3>' (aka 'const Matrix<quantity<unit<list<dim<boost::units::length_base_dimension, static_rational<1> >, boost::units::dimensionless_type>, homogeneous_system<list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > >, double>, 2, 3>') and 'const Eigen::Matrix<boost::units::quantity<boost::units::si::dimensionless, double>, 3, 1>' (aka 'const Matrix<quantity<unit<boost::units::dimensionless_type, homogeneous_system<list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > > >, double>, 3, 1>'))
        const Eigen::Matrix<boost::units::quantity<boost::units::si::length, double>, 2, 1> result = x * y;
                                                                                                     ~ ^ ~
/usr/local/include/eigen3/Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:50:29: note: candidate function [with T = Eigen::Matrix<boost::units::quantity<boost::units::unit<boost::units::list<boost::units::dim<boost::units::length_base_dimension, boost::units::static_rational<1, 1> >, boost::units::dimensionless_type>, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>, 2, 3, 0, 2, 3>]
EIGEN_MAKE_SCALAR_BINARY_OP(operator*,product)
                            ^
/usr/local/include/eigen3/Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:50:29: note: candidate function [with T = Eigen::Matrix<boost::units::quantity<boost::units::unit<boost::units::dimensionless_type, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>, 3, 1, 0, 3, 1>]
/usr/local/include/eigen3/Eigen/src/Core/MatrixBase.h:166:5: note: candidate function [with OtherDerived = Eigen::Matrix<boost::units::quantity<boost::units::unit<boost::units::dimensionless_type, boost::units::homogeneous_system<boost::units::list<boost::units::si::meter_base_unit, boost::units::list<boost::units::scaled_base_unit<boost::units::cgs::gram_base_unit, boost::units::scale<10, static_rational<3> > >, boost::units::list<boost::units::si::second_base_unit, boost::units::list<boost::units::si::ampere_base_unit, boost::units::list<boost::units::si::kelvin_base_unit, boost::units::list<boost::units::si::mole_base_unit, boost::units::list<boost::units::si::candela_base_unit, boost::units::list<boost::units::angle::radian_base_unit, boost::units::list<boost::units::angle::steradian_base_unit, boost::units::dimensionless_type> > > > > > > > > >, void>, double>, 3, 1, 0, 3, 1>]
    operator*(const MatrixBase<OtherDerived> &other) const;
    ^
/Users/dwright/projects/dv-laser-calibration/maths/Maths.cpp:6:106: warning: unused parameter 'event' [-Wunused-parameter]
Eigen::Matrix<boost::units::quantity<double>, 2, 1> Maths::convertToPhysicalCoordinates(const dv::Event &event) const {
                                                                                                         ^
In file included from /Users/dwright/projects/dv-laser-calibration/maths/Maths.cpp:1:
/Users/dwright/projects/dv-laser-calibration/maths/Maths.hpp:16:25: warning: private field 'parameters' is not used [-Wunused-private-field]
        CalibrationParameters &parameters;
                               ^
2 warnings and 1 error generated.
make[2]: *** [CMakeFiles/LaserCalibration.dir/maths/Maths.cpp.o] Error 1
make[1]: *** [CMakeFiles/LaserCalibration.dir/all] Error 2
make: *** [all] Error 2
11:04:41: The process "/usr/local/Cellar/cmake/3.17.2/bin/cmake" exited with code 2.
Error while building/deploying project LaserCalibration (kit: Imported Kit)
When executing step "CMake Build"
11:04:41: Elapsed time: 00:02.
c++ boost eigen eigen3
1个回答
1
投票

忽略共轭积特征,我可以看到第三个特化似乎不对。

template <typename scalarA, typename scalarB>
    struct ScalarBinaryOpTraits<
    scalarA, units::quantity<scalarB>,
    internal::scalar_product_op<units::quantity<scalarA>,
    units::quantity<scalarB>>> {
        typedef units::quantity<
            typename units::multiply_typeof_helper<scalarA, scalarB>::type>
            ReturnType;
    };

这一行:

    scalarA, units::quantity<scalarB>,

应该是:

    units::quantity<scalarA>, units::quantity<scalarB>,

"消除原因

我们刚才修正的第三个特殊化显然应该是与我们的情况相匹配的特殊化。但是,其他的特殊化并不排除两个标量都是一个量的情况。

把不相关的两个注释掉,确实能让事情变得通顺。

Live On Compiler Explorer

#include <boost/units/unit.hpp>
#include <boost/units/io.hpp>
#include <boost/units/limits.hpp>
#include <boost/units/quantity.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/cmath.hpp>
#include <Eigen/Core>

namespace Eigen {
    namespace units = boost::units;

#if 0
    template <typename scalarA, typename scalarB>
        struct ScalarBinaryOpTraits<
        units::quantity<scalarA>, scalarB,
        internal::scalar_product_op<units::quantity<scalarA>, scalarB>> {
            typedef units::quantity<
                typename units::multiply_typeof_helper<scalarA, scalarB>::type>
                ReturnType;
        };
#endif

#if 0
    template <typename scalarA, typename scalarB>
        struct ScalarBinaryOpTraits<
        scalarA, units::quantity<scalarB>,
        internal::scalar_product_op<scalarA, units::quantity<scalarB>>> {
            typedef units::quantity<
                typename units::multiply_typeof_helper<scalarA, scalarB>::type>
                ReturnType;
        };
#endif

#if 1
    template <typename scalarA, typename scalarB>
        struct ScalarBinaryOpTraits<
        units::quantity<scalarA>, units::quantity<scalarB>,
        internal::scalar_product_op<units::quantity<scalarA>,
        units::quantity<scalarB>>> {
            typedef units::quantity<
                typename units::multiply_typeof_helper<scalarA, scalarB>::type>
                ReturnType;
        };
#endif
} // namespace Eigen

#include <iostream>
int main() {
    using V = boost::units::quantity<boost::units::si::length, double>;
    using U = boost::units::quantity<boost::units::si::dimensionless, double>;
    constexpr auto Vu = boost::units::si::meter;
    constexpr auto Uu = 1.0;

    Eigen::Matrix<V, 2, 3> x;
    Eigen::Matrix<U, 3, 1> y;

    x << 1*Vu, 2*Vu, 3*Vu, 4*Vu, 5*Vu, 6*Vu;
    y << 1*Uu, 2*Uu, 3*Uu;

    std::cout << "x:\n" << x << "\n";
    std::cout << "y:\n" << y << "\n";
    auto result = (x * y).eval();

    std::cout << "result:\n" << result << "\n";
}

印刷品

x:
  1 m   2 m   3 m
  4 m   5 m   6 m
y:
              1 dimensionless
              2 dimensionless
              3 dimensionless
result:
  14 m
  32 m

FIX?

我想把这三者结合在一个专业里。但是 ScalarBinaryOpTraits 是不友好的SFINAE。不过我还是想弄点东西。

namespace Eigen {
    namespace units = boost::units;

    namespace /*file-static*/ {
        template <typename A, typename B, typename R = units::multiply_typeof_helper<A, B> >
        struct QuantityProductImpl {
            using ReturnType = typename R::type;
        };
    }

    template <typename A, typename B>
        struct ScalarBinaryOpTraits<A, B,
            std::enable_if_t< units::is_quantity<A>::value && units::is_quantity<B>::value,
                internal::scalar_product_op<A, B>
            >
        > : QuantityProductImpl<A, B> { };
} // namespace Eigen

就像之前一样 "Live On Compiler Explorer

然而,如果我们改变 && 变成 || (或 != 为XOR逻辑)我们又得到了歧义。不知道该如何进行,但也许能给你提供思路?

© www.soinside.com 2019 - 2024. All rights reserved.