Re: Operator overloading with templates
allan.mcrae@gmail.com wrote:
I am having trouble with overloading the += operator when template
parameters are used. I have a class holding an array (called
"derived" in the following example) which derives from a base class
("base"). I want to be able to add:
1) any derived array holding class to any other derived array holding
class
2) any derived array holding class to a literal value (e.g int,
double, etc) for which addition is defined for the type in the array.
I would like both + and += operators and for appropriate casting to be
handled. A minimal example of what I am trying to do is below (note
that the derived class holds only one value for simplicity).
The two + operators work fine with GCC (versions 3.4 and 4.1). But
the two += don't work when defined together (they work fine when
defined one at a time). When performing derived<L> += derived<R> the
operator+=(base<L,D>, R) is selected rather than
operator+=(base<L,LD>, base<R,RD>). Borland C++ Builder has this
problem and a similar one with the the binary addtion operator. I am
really confused about GCC because the operator prototypes are
practically the same, so it would seem that the the problem += and +
operators are either both correct or wrong.
Using operator+=(base<L,D>, L) works, but without automatic casting I
am after. Any suggestions on how to get around this problem, at least
in GCC would be great!
Example program (88 lines):
#include <iostream>
// curiously recurring base class
template <typename T, typename D>
class base
{
public:
T& operator[](std::size_t i) { return static_cast<D&>(*this)[i]; }
const T& operator[](std::size_t i) const { return static_cast<const
D&>(*this)[i]; }
};
// curiously recurring derived class
template <typename T>
class derived : public base<T, derived<T> >
{
public:
derived(T t) : t_(t) {}
T& operator[](std::size_t i) {return t_; }
const T& operator[](std::size_t i) const {return t_; }
private:
T t_;
};
// type promotion trait
template <typename L, typename R>
class promote
{
};
template<>
class promote<int, double>
{
public:
typedef double type;
};
// binary addition operators with casting
template <typename L, typename D, typename R>
derived<typename promote<L,R>::type>
operator+ (const base<L, D>& l, const R& r)
{
std::cout << "base + literal" << std::endl;
typedef typename promote<L,R>::type P;
return derived<P>(static_cast<P>(l[0]) + static_cast<P>(r));
}
template <typename L, typename DL, typename R, typename DR>
derived<typename promote<L,R>::type>
operator+ (const base<L, DL>& l, const base<R, DR>& r)
{
std::cout << "base + base" << std::endl;
typedef typename promote<L,R>::type P;
return derived<P>(static_cast<P>(l[0]) + static_cast<P>(r[0]));
}
// self-assigned addition
template <typename L, typename D, typename R>
void
operator+= (base<L, D>& l, const R& r)
{
std::cout << "base += literal" << std::endl;
l[0] += static_cast<L>(r);
This doesn't compile for me when instantiated from
'd2 += d3'
'R' is 'derived<double>', 'L' is 'double'. There is no conversion
from 'derived<double>' to 'double'.
The existence of the other operator+= does not matter here, I am
guessing. The reason is that with 'd3' as the second argument
the compiler cannot deduce 'R' and 'DR' from 'derived<double>'.
return;
}
template <typename L, typename DL, typename R, typename DR>
void
operator+= (base<L, DL>& l, const base<R, DR>& r)
{
std::cout << "base += base" << std::endl;
l[0] += static_cast<L>(r[0]);
return;
}
int main()
{
derived<int> d1(2);
derived<double> d2 = d1 + 3.; // base + literal
derived<double> d3 = d1 + d2; // base + base
d3 += 3.; // base += literal
d2 += d3; // base += base
}
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask