Farzam
Farzam

Reputation: 1350

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?

Upvotes: 4

Views: 4984

Answers (6)

Walter
Walter

Reputation: 45424

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.

Upvotes: 5

milleniumbug
milleniumbug

Reputation: 15814

C++11 now allows

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:

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

Upvotes: 4

peterchen
peterchen

Reputation: 41096

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 (e.g. since cin doesn't throw on invalid input, C gets assigned nan, rather than being unmodified.)


What does "clean" mean? No, don't tell me - think about it.

Upvotes: 1

MSalters
MSalters

Reputation: 179799

Inspired by Steve Jessop, it's just 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.

Upvotes: -2

jrok
jrok

Reputation: 55395

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

Upvotes: 5

fjardon
fjardon

Reputation: 7996

If you want to manipulate real parts you can just use double or floats directly. 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.

For instance, instead of writing: C.real(2*C.real() + 1); you can write: 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.

Upvotes: 2

Related Questions