通过引用传递 Complex real 和 imag
Passing Complex real and imag by reference
问题: C++11 对复数进行了一些更改,因此 real()
和 imag()
不能再被使用和滥用成员变量。
我有一些正在转换的代码,通过引用将 real()
和 imag()
传递给 sincosf()
。它看起来有点像这样:
sincosf(/*...*/, &cplx.real(), &cplx.imag());
这现在给出了 error: lvalue required as unary '&' operand
在 c++11 之前未收到哪个错误。
我的问题:是否有简单的内联修复?还是我必须创建临时变量来获取结果,然后通过设置器将它们传递给复数?
谢谢
如T.C。 在评论中,标准让你reinterpret_cast
std::complex
尽情发挥。
来自 N3337,§26.4/4 [complex.numbers]
If z
is an lvalue expression of type cv std::complex<T>
then:
— the expression reinterpret_cast<cv T(&)[2]>(z)
shall be well-formed,
— reinterpret_cast<cv T(&)[2]>(z)[0]
shall designate the real part of z
, and
— reinterpret_cast<cv T(&)[2]>(z)[1]
shall designate the imaginary part of z
.
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]
.
因此在您的代码中进行以下替换
sincosf(/*...*/,
&reinterpret_cast<T*>(&cplx)[0],
&reinterpret_cast<T*>(&cplx)[1]);
如果有一个好的优化编译器(比如,gcc -O3
),请不要认为声明临时对象仍然是一个不错的选择,并且应该与您之前所做的一样高效。
在此处查看 gcc -O3
生成的程序集:https://goo.gl/uCPAa9
使用此代码:
#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());
}
其中scf2
相当于你的说法,你可以看到三种情况下的组装非常相似。
scf1(float):
subq , %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 , %rsp
ret
scf2(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq , %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 , %rsp
popq %rbx
ret
scf3(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq , %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 , %rsp
popq %rbx
ret
随心所欲
cplx = std::polar(1.0f, /*...*/);
问题: C++11 对复数进行了一些更改,因此 real()
和 imag()
不能再被使用和滥用成员变量。
我有一些正在转换的代码,通过引用将 real()
和 imag()
传递给 sincosf()
。它看起来有点像这样:
sincosf(/*...*/, &cplx.real(), &cplx.imag());
这现在给出了 error: lvalue required as unary '&' operand
在 c++11 之前未收到哪个错误。
我的问题:是否有简单的内联修复?还是我必须创建临时变量来获取结果,然后通过设置器将它们传递给复数?
谢谢
如T.C。 reinterpret_cast
std::complex
尽情发挥。
来自 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]
.
因此在您的代码中进行以下替换
sincosf(/*...*/,
&reinterpret_cast<T*>(&cplx)[0],
&reinterpret_cast<T*>(&cplx)[1]);
如果有一个好的优化编译器(比如,gcc -O3
),请不要认为声明临时对象仍然是一个不错的选择,并且应该与您之前所做的一样高效。
在此处查看 gcc -O3
生成的程序集:https://goo.gl/uCPAa9
使用此代码:
#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());
}
其中scf2
相当于你的说法,你可以看到三种情况下的组装非常相似。
scf1(float):
subq , %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 , %rsp
ret
scf2(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq , %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 , %rsp
popq %rbx
ret
scf3(std::complex<float>&, float):
pushq %rbx
movq %rdi, %rbx
subq , %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 , %rsp
popq %rbx
ret
随心所欲
cplx = std::polar(1.0f, /*...*/);