Implicit conversion to complex<double>

P

perroe

Hi

I have a array of complex numbers that are stored in a simple double
array. This is done since the array is part of an wrapper for an
external C library, and the imaginary part of the first element, and
the last element are known to be 0. I've implemented a []-operator
that returns a ComplexReference object that basically maps a
complex<double> into the storage used in the array.

What I would like to do is using the ComplexReference object as a
complex<double> object, as shown in the code below, but I can not do
this implicitly, only through the explicit cast.

Is there any way to make this work so that the ComplexReference object
will behave like a complex<double> from the users point of view
without wrapping all the functions associated with std::complex, using
a temporary complex<double> object, or using a explicit cast?

#include "complexarray.h"

#include <complex>
#include <iostream>

int main()
{
ComplexArray a(6);

// Works:
a[0] = std::complex<double>(1.0, 0.0);
a[1] = std::complex<double>(5.1, 2.0);
a[2] = std::complex<double>(2.0, 1.1);
a[3] = std::complex<double>(5.5, 0.0);

// Does not work:
std::cout << "|a[2]| = " << std::abs(a[2]) << "\n";

// Works
std::cout << "|a[2]| = " <<
std::abs(static_cast<std::complex<double> >(a[2])) << "\n";

// Also works
std::complex<double> c = a[2];
std::cout << "|a[2]| = " << std::abs(c) << "\n";

exit(EXIT_SUCCESS);
}


complexarray.h:

#include <complex>
#include <vector>

class ComplexReference {
public:
ComplexReference(double& re, double& im)
: re_(re), im_(im) {}

inline operator std::complex<double>() const
{
return std::complex<double>(re_, im_);
}

inline ComplexReference&
operator=(const std::complex<double> c)
{
re_ = c.real();
im_ = c.imag();
return *this;
}

private:
double& re_;
double& im_;
};

class ComplexArray {
public:
typedef ComplexReference reference;
typedef std::complex<double> const_reference;

// Note: n is length of data, not number of complex elements.
explicit ComplexArray(int n = 0) : data_(n), dummy(0) {}

inline const_reference operator[](size_t i) const
{
size_t n = data_.size();
if (i == 0 || (i == n/2 && n%2 == 0)) {
return const_reference(data_, 0);
}
return const_reference(data_, data_[data_.size() - i]);
}

inline reference operator[](size_t i)
{
size_t n = data_.size();
if (i == 0 || (i == n/2 && n%2 == 0)) {
return reference(data_, dummy);
}
return reference(data_, data_[data_.size() - i]);
}

inline size_t size() const
{
return data_.size() / 2 + 1;
}

private:
/// The data vector.
std::vector<double> data_;

/// Dummy object.
double dummy;
};
 
R

Robert Bauck Hamar

Hi

I have a array of complex numbers that are stored in a simple double
array. This is done since the array is part of an wrapper for an
external C library, and the imaginary part of the first element, and
the last element are known to be 0. I've implemented a []-operator
that returns a ComplexReference object that basically maps a
complex<double> into the storage used in the array.

What I would like to do is using the ComplexReference object as a
complex<double> object, as shown in the code below, but I can not do
this implicitly, only through the explicit cast.

Is there any way to make this work so that the ComplexReference object
will behave like a complex<double> from the users point of view
without wrapping all the functions associated with std::complex, using
a temporary complex<double> object, or using a explicit cast?

Not really. One class can never behave just like another. For example, only
one user defined conversion may be called implicitly to match a function
argument. The problem with the functions associated with std::complex are
that they are templates. If you take std::abs, you have

double abs(double);
float abs(float);

and so on in <cmath>,
and the function you are interested in, is

template <class T> T abs(const complex<T>&);

And as you have seen, the compiler will not even try this. The problem is
that T cannot be deduced.
#include "complexarray.h"

#include <complex>
#include <iostream>

int main()
{
ComplexArray a(6);

// Works:
a[0] = std::complex<double>(1.0, 0.0);
a[1] = std::complex<double>(5.1, 2.0);
a[2] = std::complex<double>(2.0, 1.1);
a[3] = std::complex<double>(5.5, 0.0);

// Does not work:
std::cout << "|a[2]| = " << std::abs(a[2]) << "\n";

// Works
std::cout << "|a[2]| = " <<
std::abs(static_cast<std::complex<double> >(a[2])) << "\n";

This works because both the argument for abs and its expected parameter is
// Also works
std::complex<double> c = a[2];
std::cout << "|a[2]| = " << std::abs(c) << "\n";

//Also works:
std::cout << std::abs<double>(c);

Here, there are only one candidate, and the template parameter is selected
by hand.

//Also works
std::cout << abs(std::complex<double>(c));

This is the cast with function style syntax. At least it is shorter than
static_cast. Note that since the argument is a class from std, the compiler
will look for abs in std.
exit(EXIT_SUCCESS);

EXIT_SUCCESS is declared in said:
}


complexarray.h:

#include <complex>
#include <vector>

class ComplexReference {
public:
ComplexReference(double& re, double& im)
: re_(re), im_(im) {}

inline operator std::complex<double>() const

Note that inline is implied for functions defined inside the class
definition.
{
return std::complex<double>(re_, im_);
}

inline ComplexReference&
operator=(const std::complex<double> c)
{
re_ = c.real();
im_ = c.imag();
return *this;
}

private:
double& re_;
double& im_;
};

class ComplexArray {
public:
typedef ComplexReference reference;
typedef std::complex<double> const_reference;

// Note: n is length of data, not number of complex elements.
explicit ComplexArray(int n = 0) : data_(n), dummy(0) {}

inline const_reference operator[](size_t i) const

size_t should be a typedef. It is defined in <cstddef>, <cstdio>, <cstring>
and <ctime>, and unless you include one of the .h variants, you should use
std::size_t, or write using std::size_t. Here, however, the correct type
would be std::vector said:
{
size_t n = data_.size();
if (i == 0 || (i == n/2 && n%2 == 0)) {
return const_reference(data_, 0);
}
return const_reference(data_, data_[data_.size() - i]);
}

inline reference operator[](size_t i)
{
size_t n = data_.size();
if (i == 0 || (i == n/2 && n%2 == 0)) {
return reference(data_, dummy);
}
return reference(data_, data_[data_.size() - i]);
}

inline size_t size() const
{
return data_.size() / 2 + 1;
}

private:
/// The data vector.
std::vector<double> data_;

/// Dummy object.
double dummy;
};
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top