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<con st

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<typenam e promote<L,R>::t ype>

operator+ (const base<L, D>& l, const R& r)

{

std::cout << "base + literal" << std::endl;

typedef typename promote<L,R>::t ype P;

return derived<P>(stat ic_cast<P>(l[0]) + static_cast<P>( r));

}

template <typename L, typename DL, typename R, typename DR>

derived<typenam e promote<L,R>::t ype>

operator+ (const base<L, DL>& l, const base<R, DR>& r)

{

std::cout << "base + base" << std::endl;

typedef typename promote<L,R>::t ype P;

return derived<P>(stat ic_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

}