通过引用传递 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_caststd::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, /*...*/);