我正在寻找一个函数,它返回对C ++ 11中复数的实数或图像值的引用。在C ++ 03中我可以说:
complex<double> C; cin >> C.real();
但是在C ++ 11中,由于C.real()返回的值不是引用,因此给出了编译错误。
我发现我可以这样写:
double t; cin >> t; C.real(t);
但这并不简单,例如,如果我想将c的实部乘以2并将其加1,我应该说:
C.real(2*C.real() + 1);
那不干净。
还有其他[干净]方法吗?
答案 0 :(得分:5)
如果你真的想要为复杂的实部和虚部分开输入,你可以试试IO操纵器方法。
#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);
}
您可以将上面的代码放在自己的头文件中(如果这样做,将它包装在命名空间中可能是个好主意。)
用法:
#include <iostream>
#include "my_header.h"
int main()
{
std::complex<double> c;
std::cin >> real >> c >> imag >> c;
if (std::cin) std::cout << c;
}
希望我猜错了你对“干净”的定义:)
答案 1 :(得分:4)
很抱歉是否定的,但你的问题是从一个错误的前提开始的。关于std::complex
2011标准是向后兼容的。表格代码
complex<double> C; cin >> C.real();
永远不会有效的C ++ 。 2003标准仅给出了成员函数
T std::complext<T>::real() const;
但不是
const T& std::complext<T>::real() const; // non-standard
T& std::complext<T>::real(); // non-standard
即使某些实现(例如gcc 4.3附带的实现)可能已经实现了这两个实现。
现在,回答您的问题。显然,最简洁的方法是遵循标准的意图。 2011标准增加了以下的设定者
void std::complex<T>::real(T);
void std::complex<T>::imag(T);
因此您现在可以简单地使用它们分别设置实部或虚部。
但是,这些不能用于T&
的功能,例如operator>>
。为此,你必须做一些讨厌的技巧,我不能真正推荐:
template<typename T>
T& get_real(std::complex<T>&z) // dirty cast to gain non-const access to member.
{
struct Z { T x,y; }; // assumes that std::complex<> has same layout
static_assert(sizeof(Z)==sizeof(std::complex<T>),"!!");
static_assert(alignof(Z)==alignof(std::complex<T>),"!!");
return static_cast<Z&>(z).x;
}
std::complex<double> z;
cin >> get_real(z);
但是,这超出标准并且无法保证正常工作,因为标准没有对std::complex<>
的布局做出规定:它可以以相反的顺序存储其数据成员任何其他方式。
答案 2 :(得分:3)
C ++ 11现在允许
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];
}
用法:
std::complex<double> a;
std::cin >> re(a);
相关引用§26.4:
此外,如果a是
cv std::complex<T>*
类型的表达式,并且表达式a[i]
已为整数表达式i
定义良好,则: -reinterpret_cast<cv T*>(a)[2*i]
应指定a[i]
的真实部分,并且 -reinterpret_cast<cv T*>(a)[2*i+1]
应指定a[i]
的虚部。
答案 3 :(得分:2)
如果你想操纵实际零件,你可以直接使用double或float。
如果你想操纵虚部,你可以得到一个唯一的复数std::complex<double> I(0,1)
,然后乘以你想要的值。
例如,您可以写下:C.real(2*C.real() + 1);
C += C.real() + 1;
然后你可以在数学表达式中将双打与复数混合,编译器将使用正确的转换。查看示例:
#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;
}
输出:
$ ./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)
如果您害怕此方法的效率损失与直接通过引用影响相比,您可以查看生成的汇编代码。在g++
和-O3
的计算机上,所有内容都已内联。
答案 4 :(得分:1)
不是我知道的。
如果这对你很重要,你可以构建一个帮助者:
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);
我不会推荐使用它,但是,除非你有非常令人信服的理由。 (“我不喜欢它”并不足够令人信服。)
我认为在你的代码中有许多不同的类可能会妨碍可读性,但如果你在一些专用的实例中使用它,你应该没问题。错误处理可能变得微妙困难(例如,因为cin不会抛出无效输入,C被指定为nan,而不是未经修改。)
“干净”是什么意思?不,不要告诉我 - 想一想。
答案 5 :(得分:-2)
受史蒂夫杰西普的启发,它只是C += (C + C.conj())/2 + 1;
。
请记住,在复杂的数学中,你不能真正将实部和虚部视为完全独立的部分。这与将其相位和幅度视为完全独立的组件一样理智。复数的加法是在实部和虚部上独立完成的,但乘法是在相位和幅度部分上独立完成的。
您的示例不是复数乘法,因此std::complex
不支持这种乘法是有道理的。