自定义复杂类型和 std::complex 之间的运算符+=

发布于 2025-01-20 13:42:13 字数 2538 浏览 2 评论 0原文

我希望我的自定义复杂类型能够与STD :: Complex进行交互,但是在某些情况下,编译器不会将我的类型转换为STD :: Complex。

以下是一个最小的工作示例:

#include <complex>
#include <iostream>

template <typename Expr>
class CpxScalarExpression 
{
public:
    inline std::complex< double > eval() const { return static_cast<Expr const&>(*this).eval(); }
    
    inline operator std::complex< double >() const { return static_cast<Expr const&>(*this).eval(); }
};

class CpxScalar : public CpxScalarExpression<CpxScalar>
{
public:
    CpxScalar() : m_value(0) {}
    CpxScalar(const double value) : m_value(value) {}
    CpxScalar(const double real_value, const double imag_value) : m_value(real_value, imag_value) {}
    CpxScalar(const std::complex< double > value) : m_value(value) {}
    template<typename Expr>
    CpxScalar(const CpxScalarExpression< Expr >& expr) : m_value(expr.eval()) {}
public:
    inline std::complex< double > eval() const { return m_value; }
private:
    std::complex< double > m_value;
};

int main()
{
    CpxScalar a(10,-5);
    //std::complex< double >* b = reinterpret_cast< std::complex< double >* >(&a);
    std::complex< double > b = a;
    b += a;
    
    //std::cout << b->real() << " " << b->imag();
    std::cout << b.real() << " " << b.imag();
}

编译器在推论哪个操作员+=呼叫并返回以下错误时失败了,

est.cpp:50:4: error: no match for ‘operator+=’ (operand types are ‘std::complex<double>’ and ‘CpxScalar’)
   50 |  b += a;
      |  ~~^~~~
In file included from test.cpp:1:
/usr/include/c++/9/complex:1287:7: note: candidate: ‘std::complex<double>& std::complex<double>::operator+=(double)’
 1287 |       operator+=(double __d)
      |       ^~~~~~~~
/usr/include/c++/9/complex:1287:25: note:   no known conversion for argument 1 from ‘CpxScalar’ to ‘double’
 1287 |       operator+=(double __d)
      |                  ~~~~~~~^~~
/usr/include/c++/9/complex:1329:9: note: candidate: ‘template<class _Tp> std::complex<double>& std::complex<double>::operator+=(const std::complex<_Tp>&)’
 1329 |         operator+=(const complex<_Tp>& __z)
      |         ^~~~~~~~
/usr/include/c++/9/complex:1329:9: note:   template argument deduction/substitution failed:
test.cpp:50:7: note:   ‘CpxScalar’ is not derived from ‘const std::complex<_Tp>’
   50 |  b += a;
      |       ^

是否有办法克服此问题?

I want my custom complex type to be able to interact with std::complex, but in certain cases, the compiler do not convert my type to std::complex.

Here is a minimal working example:

#include <complex>
#include <iostream>

template <typename Expr>
class CpxScalarExpression 
{
public:
    inline std::complex< double > eval() const { return static_cast<Expr const&>(*this).eval(); }
    
    inline operator std::complex< double >() const { return static_cast<Expr const&>(*this).eval(); }
};

class CpxScalar : public CpxScalarExpression<CpxScalar>
{
public:
    CpxScalar() : m_value(0) {}
    CpxScalar(const double value) : m_value(value) {}
    CpxScalar(const double real_value, const double imag_value) : m_value(real_value, imag_value) {}
    CpxScalar(const std::complex< double > value) : m_value(value) {}
    template<typename Expr>
    CpxScalar(const CpxScalarExpression< Expr >& expr) : m_value(expr.eval()) {}
public:
    inline std::complex< double > eval() const { return m_value; }
private:
    std::complex< double > m_value;
};

int main()
{
    CpxScalar a(10,-5);
    //std::complex< double >* b = reinterpret_cast< std::complex< double >* >(&a);
    std::complex< double > b = a;
    b += a;
    
    //std::cout << b->real() << " " << b->imag();
    std::cout << b.real() << " " << b.imag();
}

The compiler fails at deducing which operator+= to call and returns the following error

est.cpp:50:4: error: no match for ‘operator+=’ (operand types are ‘std::complex<double>’ and ‘CpxScalar’)
   50 |  b += a;
      |  ~~^~~~
In file included from test.cpp:1:
/usr/include/c++/9/complex:1287:7: note: candidate: ‘std::complex<double>& std::complex<double>::operator+=(double)’
 1287 |       operator+=(double __d)
      |       ^~~~~~~~
/usr/include/c++/9/complex:1287:25: note:   no known conversion for argument 1 from ‘CpxScalar’ to ‘double’
 1287 |       operator+=(double __d)
      |                  ~~~~~~~^~~
/usr/include/c++/9/complex:1329:9: note: candidate: ‘template<class _Tp> std::complex<double>& std::complex<double>::operator+=(const std::complex<_Tp>&)’
 1329 |         operator+=(const complex<_Tp>& __z)
      |         ^~~~~~~~
/usr/include/c++/9/complex:1329:9: note:   template argument deduction/substitution failed:
test.cpp:50:7: note:   ‘CpxScalar’ is not derived from ‘const std::complex<_Tp>’
   50 |  b += a;
      |       ^

Is there a way to overcome this issue ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自由如风 2025-01-27 13:42:14

为操作员提供自己的超负荷是必经之路。

但是,有几件事要牢记:

  • 由于您已经有一个可用的铸件,所以您要做的就是使用它,让常规操作员从那里拿走它。

  • 由于要“姿势”为std ::复杂 IS cpxScalarexpression&lt; expr&gt;,因此应该是过载在。<<<<<<<<<< /p>

  • std ::复杂's 操作员+=()通常允许您添加不同类型的复杂值,因此我们应该维护。这意味着应将操作员在输入std :: Complex的组件类型上进行模板。

  • 我们需要确保返回恰好 std ::复杂's 操作员+=想要返回。使用electType(auto)作为过载的返回类型为您提供。

将所有这些放在一起,我们将其放在:

template<typename T, typename Expr>
constexpr decltype(auto) operator+=(
        std::complex<T>& lhs,
        const CpxScalarExpression<Expr>& rhs) {
    return lhs += std::complex<double>(rhs);
}

将其放入您发布的代码中,使其正常工作,并应为您提供std :: complect's operator+=(( )

Providing your own overload for the operator is the way to go.

However, there's a few things to keep in mind:

  • Since you already have a cast available, all you have to do is to use it and let the regular operator take it from there.

  • Since the type that is meant to "pose" as std::complex is CpxScalarExpression<Expr>, then that should be the one the overload operates on.

  • std::complex's operator+=() normally allows you to add together complex values of different types, so we should maintain that. Meaning the operator should be templated on the incoming std::complex's components type.

  • We need to make sure to return exactly whatever std::complex's operator+= wants to return. Using decltype(auto) as the return type of the overload provides you with just that.

Putting all of that together, we land at:

template<typename T, typename Expr>
constexpr decltype(auto) operator+=(
        std::complex<T>& lhs,
        const CpxScalarExpression<Expr>& rhs) {
    return lhs += std::complex<double>(rhs);
}

Dropping that into the code you posted makes it work just as expected, and should give you feature parity with std::complex's operator+=().

征﹌骨岁月お 2025-01-27 13:42:14

+=的自定义操作员与您的示例一起使用:

[[maybe_unused]] constexpr static inline std::complex<double> operator+=(
        const std::complex<double>& lhs,
        const CpxScalar&            rhs) noexcept {
    return lhs + rhs.eval();
}

A custom operator for += works with your example:

[[maybe_unused]] constexpr static inline std::complex<double> operator+=(
        const std::complex<double>& lhs,
        const CpxScalar&            rhs) noexcept {
    return lhs + rhs.eval();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文