Now this really took me by surprise and I just believed it after extensive debugging. Here's the punchline: A templated operator= is not used for assignments from the same data-type. That means when test has a templated operator=, this does not call it:
test a, b;
a = b;
On a second thought, this is actually comprehensible behaviour. The compiler generates a default operator= for assignments of it's own type that calls operator= for each member. This default operator is even generated when a templated operator exists. And because overloaded functions have stronger "binding" than template-functions, the implicitly created and therefore overloading operator= is called. Here's an example:
#include <iostream>
struct test
{
template<typename T>
test &operator=(const T &value)
{
std::cout << "template operator=()" << std::endl;
return *this;
}
};
int main()
{
test a, b;
b = 10;
a = b;
}
You might think that the output is
operator=()
operator=()
but it isn't. The output contains only one line, because the generated operator= does not create any output.
It is extremely important to know this rule and don't fall into it's trap like I did. In my case I had a pointer-member and simply assigning it resulted in a double-free in the dtor of the last destroyed copy of that object. Here's the correct way to circumvent this:
#include <iostream>
struct test
{
template<typename T>
test &operator=(const T &value)
{
std::cout << "template operator=()" << std::endl;
return *this;
}
test &operator=(const test &value)
{
return operator=<test>(value);
}
};
int main()
{
test a, b;
b = 10;
a = b;
}