Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. In C++03 I could say:

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.

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.real(2*C.real() + 1);

That is not clean.

Is there any other [clean] way to do that?

like image 863
Farzam Avatar asked Dec 11 '22 10:12

Farzam


2 Answers

If you really want to separate input for real and imaginary parts of a complex, you could try IO manipulators approach.

#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 :)

like image 58
jrok Avatar answered Dec 28 '22 23:12

jrok


Sorry to be negative, but your question starts from a wrong premise. Concerning std::complex the 2011 standard is backward compatible. Code of the form

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

was never valid C++. The 2003 standard only gives the member function

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.

Now, to answer your question. Clearly, the cleanest way is to follow the intention of the standard. The 2011 standard adds the following setters

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>>. 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.

like image 26
Walter Avatar answered Dec 28 '22 22:12

Walter