From: Bo on
Hi all,

Below is a short program where I define a class A, in which I redefine
the operator =.

Inside the operator implementation, it just prints a line to notify
that it is indeed the new assignment operator which is called.

In main(), I define two variables a and b, both of the same type
A<int>. Then I write "a = b", where I expect that the new operator=
will be called. I expect that the compiler can figure out that "T =
int" and "S = int".

However, this is not the case. As the program is running, the new
operator is not called. It is the default operator= which is used.
Now, if I change the definition of "b" to "A<float> b", then the new
operator= is used.

Why the compiler cannot figure out in the first case that "T = int"
and "S = int" ?

------------------------
#include <iostream>
using namespace std;

template <class T>
class A
{
public:
template <class S>
A<T>& operator = (const A<S>& a)
{
cerr << "inside operator =" << endl;
return *this;
}
};

int main()
{
A<int> a;
A<int> b;

a = b; // the redefined assingment operator is NOT called.
// If I declare A<float> b, then the new operator is
called.
}
-------------------------------

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas Maeder on
Bo <bo.zhang0609(a)gmail.com> writes:

> Below is a short program where I define a class A, in which I redefine
> the operator =.

You don't "redefine" it. You overload it.


> Inside the operator implementation, it just prints a line to notify
> that it is indeed the new assignment operator which is called.
>
> In main(), I define two variables a and b, both of the same type
> A<int>. Then I write "a = b", where I expect that the new operator=
> will be called. I expect that the compiler can figure out that "T =
> int" and "S = int".

More importantly, the compiler figures out that both operands are of
the same type, i.e. the expression involves copy-assignment.


> However, this is not the case. As the program is running, the new
> operator is not called. It is the default operator= which is used.
> Now, if I change the definition of "b" to "A<float> b", then the new
> operator= is used.
>
> Why the compiler cannot figure out in the first case that "T = int"
> and "S = int" ?

Because the Standard tells it not to.

Copy-assignment operator and copy-constructor are not generated from
member templates. If required, they are generated "the regular
way". And if one object of the class in question is assigned to
another, that copy-assignment operator, being a perfect match, is a
better match than any operator generated from a template.

Cf. ISO C++ Standard (1998) 12.8/2, footnote 106, 12.8/9, footnote
109.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Greg Herlihy on
On Jun 27, 1:24 pm, Bo <bo.zhang0...(a)gmail.com> wrote:
> Below is a short program where I define a class A, in which I redefine
> the operator =.

No, the program below does not "redefine" operator= for the A class
template; instead it overloads operator=. In other words, the program
adds an operator= to A (to support assigning new types to an A
object), but otherwise the overloaded operator= does not replace any
of A's existing assignment methods.

> In main(), I define two variables a and b, both of the same type
> A<int>. Then I write "a = b", where I expect that the new operator=
> will be called. I expect that the compiler can figure out that "T =
> int" and "S = int".
>
> #include <iostream>
> using namespace std;
>
> template <class T>
> class A
> {
> public:
> template <class S>
> A<T>& operator = (const A<S>& a)
> {
> cerr << "inside operator =" << endl;
> return *this;
> }
> };
>
> int main()
> {
> A<int> a;
> A<int> b;
>
> a = b; // the redefined assingment operator is NOT called.
> // If I declare A<float> b, then the new operator is
> // called.
> }
>
> Why the compiler cannot figure out in the first case that "T = int"
> and "S = int" ?

The compiler does indeed figure out that both T and S are "int" types;
but more importantly, the compiler also recognizes that then when T
and S are the same type, then "a" and "b" also have the same type. And
whenever a class object ia assigned the value of a class object of the
same type, the compiler calls the class's "copy-assignment method"
which - if not explicitly defined - is implicitly generated by the
compiler.

Now, because the overloaded operator= in the program above does not
meet the criteria for a copy assignment operator - the program (to
assign b to a) calls A<int>'s implicit copy assignment operator,
instead. In other words, when b is assigned to a, the program calls
the same (implicit) copy assignment operator that the program would
have called - if no overloaded operator=() existed. So, as pointed out
earlier, a function template operator=() does not override (that is,
redefine) the class's implicit copy assignment operator.

So the solution to the problem of operator= not being called when
copying b to a, would be to override A's implicit copy assignment
operator with an explicit method:

A& operator=(const A& a)
{
cerr << "inside copy assignment\n";
return *this;
}

Greg


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Hoobert on
>
> template <class T>
> class A
> {
> public:
> template <class S>
> A<T>& operator = (const A<S>& a)
> {
> cerr << "inside operator =" << endl;
> return *this;
> }
> };

Assignment operator assigns from another object of *exactly* the same
type. So in your case it would be if you have const A<T> &a.

> int main()
> {
> A<int> a;
> A<int> b;
>
> a = b; // the redefined assingment operator is NOT called.
> // If I declare A<float> b, then the new operator is
> called.
> }
> -------------------------------
>
Here implicit assignment operator is called.
See in standard 12.8, 12.9.

Regards

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Chris Uzdavinis on
On Jun 27, 4:24 pm, Bo <bo.zhang0...(a)gmail.com> wrote:

....
> In main(), I define two variables a and b, both of the same type
> A<int>. Then I write "a = b", where I expect that the new operator=
> will be called. I expect that the compiler can figure out that "T =
> int" and "S = int".
>
> However, this is not the case. As the program is running, the new
> operator is not called. It is the default operator= which is used.
> Now, if I change the definition of "b" to "A<float> b", then the new
> operator= is used.
>
> Why the compiler cannot figure out in the first case that "T = int"
> and "S = int" ?


According to the standard (see footnote 109 in section 12.8), copy
constructors cannot be templates. However, when you assign a to b,
you are invoking the copy constructor. It's not the case that the
compiler cannot figure out in the first case that "T = int" and "S =
int". It's just that the compiler is not supposed to!

In all situations, when the compiler has a choice, a non-template
function with exact type match is preferred over any other template
function that might also be capable of matching.

--
Chris

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]