|
Prev: Why not reject the dynamic instantiation of a class with non-virtual destructor?
Next: problem with iterator declaration within template
From: Bo on 27 Jun 2008 05:24 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 27 Jun 2008 16:28 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 27 Jun 2008 16:28 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 27 Jun 2008 16:27 > > 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 27 Jun 2008 16:28
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! ] |