简体   繁体   English

在C ++ 11中返回对复数的实数或图像值的引用的函数

[英]a function returning reference to real or imag values of a complex number in C++11

I'm looking for a function that returns a reference to real or imag values of a complex number in C++11. 我正在寻找一个函数,它返回对C ++ 11中复数的实数或图像值的引用。 In C++03 I could say: 在C ++ 03中,我可以说:

complex<double> C; cin >> C.real();

But in C++11 that gives me a compile error since the C.real() returns a value not a reference. 但是在C ++ 11中,由于C.real()返回的值不是引用,因此给出了编译错误。

I found out that I can write this: 我发现我可以这样写:

double t; cin >> t; C.real(t);

but it isn't straightforward and for example if I want to multiply the real part of c by 2 and ad it by 1 I should say: 但它并不简单,例如,如果我想将c的实部乘以2并将其加1,我应该说:

C.real(2*C.real() + 1);

That is not clean. 那不干净。

Is there any other [clean] way to do that? 还有其他[干净]的方法吗?

If you really want to separate input for real and imaginary parts of a complex, you could try IO manipulators approach. 如果您真的想要为复杂的实部和虚部分开输入,可以尝试IO操纵器方法。

#include <complex>
#include <iosfwd>

class proxy_complex {
    explicit proxy_complex(std::istream& strm, bool f)
        : strm_(&strm), flag(f) { }
    proxy_complex(const proxy_complex&) = default;

    std::istream* strm_;
    bool flag;           // flag to check whether we're writing real or imag

public:
    template<typename T>
    std::istream& operator>>(std::complex<T>& c)
    {
        T n;
        if (*strm_ >> n)
            flag ? c.real(n) : c.imag(n);
        return *strm_;
    }

    friend proxy_complex operator>>(std::istream& is, proxy_complex(*func)(std::istream&))
    {
        return func(is);
    }
    friend proxy_complex real(std::istream&);
    friend proxy_complex imag(std::istream&);
};

inline proxy_complex real(std::istream& is)
{
    return proxy_complex(is, true);
}

inline proxy_complex imag(std::istream& is)
{
    return proxy_complex(is, false);
}

You can put the above code in a header file of its own (if you do that, it might be a good idea to wrap it in a namespace). 您可以将上面的代码放在自己的头文件中(如果这样做,将它包装在命名空间中可能是个好主意)。

Usage: 用法:

#include <iostream>
#include "my_header.h"

int main()
{
    std::complex<double> c;
    std::cin >> real >> c >> imag >> c;
    if (std::cin) std::cout << c;
}

Hope I guessed your definition of "clean" correctly :) 希望我猜对你正确定义“干净”:)

Sorry to be negative, but your question starts from a wrong premise. 很抱歉是否定的,但你的问题是从一个错误的前提开始的。 Concerning std::complex the 2011 standard is backward compatible. 关于std::complex ,2011标准是向后兼容的。 Code of the form 表格代码

complex<double> C; cin >> C.real();

was never valid C++ . 从来没有有效的C ++ The 2003 standard only gives the member function 2003标准仅给出了成员函数

T std::complext<T>::real() const;

but not 但不是

const T& std::complext<T>::real() const;  // non-standard
T& std::complext<T>::real();              // non-standard

even though some implementations (such as that shipped with gcc 4.3) may have implemented these two instead. 即使某些实现(例如gcc 4.3附带的实现)可能已经实现了这两个实现。

Now, to answer your question . 现在, 回答你的问题 Clearly, the cleanest way is to follow the intention of the standard. 显然,最简洁的方法是遵循标准的意图。 The 2011 standard adds the following setters 2011年标准增加了以下制定者

void std::complex<T>::real(T);
void std::complex<T>::imag(T);

so you can now simply use those to set the real or imaginary parts separately. 所以你现在可以简单地用它们分别设置实部或虚部。

However, those cannot be used in a function taking T& , such as operator>> . 但是,那些不能用于服用T&的函数,例如operator>> For that you must do some nasty tricks like 为此,你必须做一些令人讨厌的技巧

template<typename T>
inline T& get_real(std::complex<T>&z) { return reinterpret_cast<T(&)[2]>(z)[0]; }

template<typename T>
inline T& get_imag(std::complex<T>&z) { return reinterpret_cast<T(&)[2]>(z)[1]; }

std::complex<double> z;
cin >> get_real(z) >> get_imag(z);

Actually, as pointed out in a comment by bames53, the standard guarantees std::complex to be laid out such that this always works. 实际上,正如bames53的评论中指出的那样,标准保证std::complex布局使得它始终有效。

C++11 now allows C ++ 11现在允许

double& re(std::complex<double>& c)
{
    return reinterpret_cast<double (&)[2]>(c)[0];
}

double& im(std::complex<double>& c)
{
    return reinterpret_cast<double (&)[2]>(c)[1];
}

const double& re(const std::complex<double>& c)
{
    return reinterpret_cast<const double (&)[2]>(c)[0];
}

const double& im(const std::complex<double>& c)
{
    return reinterpret_cast<const double (&)[2]>(c)[1];
}

Usage: 用法:

std::complex<double> a;
std::cin >> re(a);

Relevant quote §26.4: 相关引用§26.4:

Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i , then: — reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i] , and — reinterpret_cast<cv T*>(a)[2*i+1] shall designate the imaginary part of a[i] . 此外,如果a是cv std::complex<T>*类型的表达式,并且表达式a[i]为整数表达式i定义良好,则: - reinterpret_cast<cv T*>(a)[2*i]应指定a[i]的实部,并且 - reinterpret_cast<cv T*>(a)[2*i+1]应指定a[i]的虚部。

If you want to manipulate real parts you can just use double or floats directly. 如果你想操纵实际零件,你可以直接使用double或float。 If you want to manipulate imaginary parts you can have a unique complex number std::complex<double> I(0,1) and multiply it by the value you want. 如果你想操纵虚部,你可以有一个唯一的复数std::complex<double> I(0,1)并将它乘以你想要的值。

For instance, instead of writing: C.real(2*C.real() + 1); 例如,而不是写: C.real(2*C.real() + 1); you can write: C += C.real() + 1; 你可以写: C += C.real() + 1;

Then you can mix doubles with complexs in your mathematical expressions and the compiler will use the correct conversions. 然后,您可以在数学表达式中将双精度数与复数形式混合使用,编译器将使用正确的转换。 See an example: 看一个例子:

#include <iostream>
#include <complex>

int main(int argc, char* argv[])
{
    // Let the user enter a Real number
    double c;
    std::cin >> c;

    // Explicitly convert to a complex
    std::complex<double> C = 2*c + 1;
    std::cout << C << std::endl;

    // Creates a pure imaginary complex number I
    std::complex<double> I(0,1);

    // Mix together complex and real numbers in the
    // same expression
    C = C + c*I;
    std::cout << C << std::endl;


    // Setup a specific value and compare how to achieve
    // C.real = 2*C.real + 1
    C = 1. + 2.*I;
    C.real(2*C.real()+1);
    std::complex<double> D = 1. + 2.*I;
    D += D.real() + 1;
    std::cout << "C=" << C << "\tD=" << D << std::endl;

    return 0;
}

The output: 输出:

$ ./main.exe
1
(3,0)
(3,1)
C=(3,2) D=(3,2)

$ ./main.exe
2
(5,0)
(5,2)
C=(3,2) D=(3,2)

If you are afraid of the lost of efficiency of this method compared to affecting directly through a reference you can look at the generated assembly code. 如果您害怕此方法的效率损失与直接通过引用影响相比,您可以查看生成的汇编代码。 On my computer with g++ and -O3 everything is inlined. 在我的计算机上使用g++-O3所有内容都是内联的。

Not that I know of. 从来没听说过。

You could construct a helper if that's important to you: 如果这对您很重要,您可以构建一个帮助程序:

class ModifyReal
{
   double d;
   complex<double> & c;
public:
   ModifyReal(complex<double> & c_) : c(c_), d(numeric_limits<double>::quiet_NaN()) 
   {}
   operator double &() { return d; }
   ~ModifyReal() { c.real(d); }
};


cin >> ModifyReal(C);

I would not exactly recommend to use this, however, unless you have a very compelling reason to. 但是,我不建议使用它,除非你有一个非常令人信服的理由。 ("I do not like it" is not convincing enough.) (“我不喜欢它”不够令人信服。)

I do think having many different classes like this in your code can hamper readability, but if you use it in a few dedicated instances you should be fine. 我认为在你的代码中有许多不同的类可能会妨碍可读性,但如果你在一些专用实例中使用它,你应该没问题。 Error handling can become subtley difficult (eg since cin doesn't throw on invalid input, C gets assigned nan, rather than being unmodified.) 错误处理可能变得非常困难(例如,由于cin不会抛出无效输入,因此C被指定为nan,而不是未经修改。)


What does "clean" mean? “干净”是什么意思? No, don't tell me - think about it. 不,不要告诉我 - 考虑一下。

Inspired by Steve Jessop, it's just C += (C + C.conj())/2 + 1; 受Steve Jessop的启发,它只是C += (C + C.conj())/2 + 1; .

Remember that in complex math, you cannot really treat the real and imaginary parts as fully independent components. 请记住,在复杂的数学中,您无法将实部和虚部视为完全独立的组件。 That's just about as sane than treating their phase and magnitude as fully independent components. 这与将其相位和幅度视为完全独立的组件一样理智。 Addition of complex numbers is done independently on real and imaginary parts, but multiplication is done independently on the phase and magnitude parts. 复数的加法是在实部和虚部上独立完成的,但乘法是在相位和幅度部分上独立完成的。

Your example is not complex multiplication, so it makes sense that std::complex doesn't support that kind of multiplication. 你的例子不是复杂的乘法,所以std::complex不支持这种乘法是有意义的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM