Implicit conversion to complex<double>

Discussion in 'C++' started by perroe@nr.no, Jul 12, 2007.

  1. Guest

    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;
    };

    --
    Per Røe
    , Jul 12, 2007
    #1
    1. Advertising

  2. wrote:

    > 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
    on the form
    std::complex<T>,
    which means T can be deduced.

    >
    > // 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 <cstdlib>/<stdlib.h>

    > }
    >
    >
    > 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<double>::size_type.

    > {
    > 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;
    > };


    --
    rbh
    Robert Bauck Hamar, Jul 12, 2007
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sydex
    Replies:
    12
    Views:
    6,489
    Victor Bazarov
    Feb 17, 2005
  2. Arvid Requate
    Replies:
    2
    Views:
    983
    Alf P. Steinbach
    Jun 23, 2006
  3. J.M.
    Replies:
    3
    Views:
    630
    Sarath
    Mar 6, 2007
  4. Replies:
    5
    Views:
    429
    James Kanze
    Jun 27, 2008
  5. Replies:
    7
    Views:
    397
    Greg Herlihy
    Jul 2, 2008
Loading...

Share This Page