Reputation: 161
The Problem: C++11 has made some changes to complex numbers so that real()
and imag()
can no longer be used and abused like member variables.
I have some code that I am converting over that passes real()
and imag()
to sincosf()
by reference. It looks a little like this:
sincosf(/*...*/, &cplx.real(), &cplx.imag());
This now gives a error: lvalue required as unary '&' operand
which error was not received prior to c++11.
My Question: Is there an easy inline fix? or do I have to create temporary variables to get the result and then pass those to the complex number via setters?
Thanks
Upvotes: 3
Views: 734
Reputation: 3769
Do not that declaring temporaries still is a good option and should be just as efficient as what you are previously doing, given a good optimizing compiler (say, gcc -O3
).
See the resulting assembly from gcc -O3
here: https://goo.gl/uCPAa9
Using this code:
#include<complex>
std::complex<float> scf1(float x) {
float r = 0., i = 0.;
sincosf(x, &r, &i);
return std::complex<float>(r, i);
}
void scf2(std::complex<float>& cmp, float x) {
float r = 0., i = 0.;
sincosf(x, &r, &i);
cmp.real(r);
cmp.imag(i);
}
void scf3(std::complex<float>& cmp, float x) {
float r = 0., i = 0.;
sincosf(x, &cmp.real(), &cmp.imag());
}
Where scf2
is equivalent to your statement, you can see very similar assembly in the three cases.
scf1(float):
subq $24, %rsp
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdi
call sincosf
movss 12(%rsp), %xmm0
movss %xmm0, (%rsp)
movss 8(%rsp), %xmm0
movss %xmm0, 4(%rsp)
movq (%rsp), %xmm0
addq $24, %rsp
ret
scf2(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq $16, %rsp
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdi
call sincosf
movss 12(%rsp), %xmm0
movss %xmm0, (%rbx)
movss 8(%rsp), %xmm0
movss %xmm0, 4(%rbx)
addq $16, %rsp
popq %rbx
ret
scf3(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq $16, %rsp
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdi
call sincosf
movss 12(%rsp), %xmm0
movss %xmm0, (%rbx)
movss 8(%rsp), %xmm0
movss %xmm0, 4(%rbx)
addq $16, %rsp
popq %rbx
ret
Upvotes: 0
Reputation: 109119
As T.C. mentions in the comments, the standard allows you to reinterpret_cast
std::complex
to your heart's content.
From N3337, §26.4/4 [complex.numbers]
If
z
is an lvalue expression of type cvstd::complex<T>
then:
— the expressionreinterpret_cast<cv T(&)[2]>(z)
shall be well-formed,
—reinterpret_cast<cv T(&)[2]>(z)[0]
shall designate the real part ofz
, and
—reinterpret_cast<cv T(&)[2]>(z)[1]
shall designate the imaginary part ofz
.
Moreover, ifa
is an expression of type cvstd::complex<T>*
and the expressiona[i]
is well-defined for an integer expressioni
, then:
—reinterpret_cast<cv T*>(a)[2*i]
shall designate the real part ofa[i]
, and
—reinterpret_cast<cv T*>(a)[2*i + 1]
shall designate the imaginary part ofa[i]
.
So make the following replacement in your code
sincosf(/*...*/,
&reinterpret_cast<T*>(&cplx)[0],
&reinterpret_cast<T*>(&cplx)[1]);
Upvotes: 3