Operator overloading with templates
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);
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
}