Arithmetic conversions/promotion and templates

  • Thread starter =?ISO-8859-1?Q?Christian_Brechb=FChler?=
  • Start date
?

=?ISO-8859-1?Q?Christian_Brechb=FChler?=

Let me use complex numbers as a familiar example. The following is
taken verbatim from Bjarne Stroustrup, "The C++ Programming Language",
except the include line and the "no match" comments. It won't compile.



#include <complex>

// section 22.5:
// Throughout this book, I have used complex as a class rather than as a
// template. This is feasible because I assumed a bit of namespace magic to
// get the complex of double that I usually prefer:
typedef std::complex<double> complex;

// section 11.3:
// For example, from looking at a math textbook we would expect this to
work:
void f()
{
complex a = complex(1,2);
complex b = 3;
complex c = a+2.3;
complex d = 2+b; // no match for `int + complex&' operator
complex e = -b-c;
b = c*2*c; // no match for `complex& * int' operator
}



(Obviously we could kludge it by replacing 2 by 2.0 or double(2) etc.,
but I think we rightfully expect it to work exactly as Stroustrup wrote it.)

Questions: What was the rationale for implementing the standard library
like this?
Is there a generic way to accept any type that the usual arithmetic
conversions (C.6.3) can promote to double as the left or right argument
to a binary operator?

(I tried templating on the "simple" type, but when I do it for the left
and right argument, a+b becomes ambiguous. -- I there a way to express
that a template parameter "class T" must have a conversion to double?)

Thanks

Christian
 
V

Victor Bazarov

Christian Brechbühler said:
Let me use complex numbers as a familiar example. The following is
taken verbatim from Bjarne Stroustrup, "The C++ Programming Language",
except the include line and the "no match" comments. It won't compile.



#include <complex>

// section 22.5:
// Throughout this book, I have used complex as a class rather than as a
// template. This is feasible because I assumed a bit of namespace magic to
// get the complex of double that I usually prefer:
typedef std::complex<double> complex;

// section 11.3:
// For example, from looking at a math textbook we would expect this to
work:
void f()
{
complex a = complex(1,2);
complex b = 3;
complex c = a+2.3;
complex d = 2+b; // no match for `int + complex&' operator
complex e = -b-c;
b = c*2*c; // no match for `complex& * int' operator
}



(Obviously we could kludge it by replacing 2 by 2.0 or double(2) etc.,
but I think we rightfully expect it to work exactly as Stroustrup wrote it.)

Questions: What was the rationale for implementing the standard library
like this?

This is a question for comp.std.c++. They discuss the "why" questions.
We here discuss the "how".
Is there a generic way to accept any type that the usual arithmetic
conversions (C.6.3) can promote to double as the left or right argument
to a binary operator?

Yes.

#include <complex>

typedef std::complex<double> complex;

template<class T>
complex operator +(const complex& c, T t) {
return std::eek:perator +(c,complex(t)); // call the std:: one
}

void foo() {
complex a(1,2);
complex b = 2 + a; // ours works fine
}

(I tried templating on the "simple" type, but when I do it for the left
and right argument, a+b becomes ambiguous. -- I there a way to express
that a template parameter "class T" must have a conversion to double?)

I am not sure what you're saying here. Please supply the code.

Victor
 
G

Gianni Mariani

Christian said:
Questions: What was the rationale for implementing the standard library
like this?

I don't know.
Is there a generic way to accept any type that the usual arithmetic
conversions (C.6.3) can promote to double as the left or right argument
to a binary operator?

(I tried templating on the "simple" type, but when I do it for the left
and right argument, a+b becomes ambiguous. -- I there a way to express
that a template parameter "class T" must have a conversion to double?)

I think you may need to be more generic with your example because
you can supply your own operators that solves the complex problem.

template <typename T>
inline complex<T> operator+ (
const typename complex<T>::value_type & r,
const complex<T> & c
)
{
return complex<T>( r, 0 ) + c;
}

template <typename T>
inline complex<T> operator* (
const complex<T> & c,
const typename complex<T>::value_type & r
)
{
return c * complex<T>( r, 0 );
}
 
?

=?ISO-8859-1?Q?Christian_Brechb=FChler?=

Victor said:
Yes.

#include <complex>

typedef std::complex<double> complex;

template<class T>
complex operator +(const complex& c, T t) {
return std::eek:perator +(c,complex(t)); // call the std:: one
}

void foo() {
complex a(1,2);
complex b = 2 + a; // ours works fine
}

Cool, thanks! I see it works, but how? With T=int, your definition
explicitly defines the operator complex + int. But apparently at the
same time it defines int + complex!
Your definition supports 2 + a and a + 2. Why?

I had tried something that looks superficially the same, except it
doesn't use typedef:



#include <complex>

template<class T, class Real>
std::complex<Real> operator +(const std::complex<Real>& c, T t) {
return std::eek:perator +(c,std::complex<Real>(t));
}

void foo() {
std::complex<double> a(1,2);
std::complex<double> b = 2 + a; // error: no match
std::complex<double> c = a + 2;
}



And here only one of the operators gets defined.

Thanks again to Victor for the quick and neat answer!

Christian
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top