Topic: specialising std::complex


Author: "kwikius" <andy@servocomm.freeserve.co.uk>
Date: Mon, 17 Jul 2006 09:02:58 CST
Raw View
Suppose I have three classes resistance, current and voltage

resistance r = voltage() / current();

However I can also have complex resistances, currents and voltages:

std::complex<resistance> z
    = std::complex<voltage>() / std::complex<current>();

(I would have to specialise std::complex for these types)

However the std:: signature for complex multiplication looks like so:

complex<T> operator/ (complex<T> const &, complex<T> const &);

whereas my version would look like (using a simulated typeof):

complex<typeof(T1() / T2()) > operator/ (complex<T1> const &,
complex<T2> const &);

Am I allowed to specialise this in std?

regards
Andy Little

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Richard Smith" <richard@ex-parrot.com>
Date: Mon, 17 Jul 2006 10:59:49 CST
Raw View
kwikius wrote:
> Suppose I have three classes resistance, current and voltage
>
> resistance r = voltage() / current();
>
> However I can also have complex resistances, currents and voltages:
>
> std::complex<resistance> z
>     = std::complex<voltage>() / std::complex<current>();
>
> (I would have to specialise std::complex for these types)

Yes.  You can specialise almost any standard library component:

[17.4.3.1] "A program may add template specializations for any standard
library template to namespace std.  Such a specialization (complete or
partial) of a standard library template results in undefined behaviour
unless the declaration depends on a user-defined name ..."

Unfortunately this isn't sufficient as you also have to deal with the
namespace-scope operators such as operator/.  As you are not allowed to
inject overloads (only specialisations) into namespace std, and you
cannot partially specialise a function template, this has to be done
some other way.  Fortunately ADL provides a way of doing this:


namespace myns {
  template <typename T, int Kg, int M, int S, int A>
  struct dimension;

  typedef dimension<double, 0,0,0,1> current;
  typedef dimension<double, 1,2,-3,-1> voltage;
  typedef dimension<double, 1,2,-3,-2> resistance;

  template <typename T, int Kg1, int M1, int S1, int A1,
                        int Kg2, int M2, int S2, int A2>
  std::complex< dimension<T, Kg1-Kg2, M1-M2, S1-S2, A1-A2> >
  operator/( std::complex< dimension<T, Kg1, M1, S1, A1> > const&,
             std::complex< dimension<T, Kg2, M2, S2, A2> > const& );

  template <typename T, int Kg, int M, int S, int A>
  std::complex<T>
  operator/( std::complex< dimension<T, Kg, M, S, A> > const&,
             std::complex< dimension<T, Kg, M, S, A> > const& );
}

int main() {
  std::complex< myns::voltage    > V;
  std::complex< myns::current    > I;
  std::complex< myns::resistance > Z = V/I;
  std::complex< double           > U = I/I;
}

The second operator/ overload is needed because otherwise dividing two
quantities of the same dimension is ambiguous. You need it even if you
don't want the different return type (as I've given it).

--
Richard Smith

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]