Small problem with C template and overload
A few days ago and a friend discussed a small problem about C template and overload. I remember the code that originally found the problem:
#include
#include
Using namespace std;
Class node
{
PUBLIC:
Int m;
Node (int value): m (value) {}
Friend Ostream & Operator << (Ostream & O, Const Node * & P);
}
Ostream & Operator << (Ostream & O, Const Node * & P)
{
O << p-> m << ENDL;
Return O;
}
int main ()
{
Node * p = new node (10);
Cout << p << endl;
List
l.push_back (p);
Copy (L. Segin (), L.End (), Ostream_Iterator
}
The above code first displays Node content in a manner such as "cout << p", as the "<<" operator has been overloaded, and the result is 10, correct. But then use the COPY function to "copy" "copy" in the list to Cout, when the Node content is displayed, the program only shows the memory address stored in the P, not the content of Node points to the content, which is expected. The result is not met.
I haven't used the syntax directly to Ostream_iterator plus COPY (this can save the trouble of writing loops), not very familiar with the mechanism. At first, I think this is because the COPY function in the STL is just simply assigning the value, and there is no call for the Operator << function, so no node content is displayed. But very quickly, the friend pointed out that although the copy function is assigned, the ostream_iterator class is overloaded to assignment operators:
ostream_iterator <_ty, _lex, _traits> & operator = (const _ty & _val)
{// INSERT VALUE INTO OUTPUT Stream, Followed by Delimiter
* _MYOSTR << _val;
IF (_mydelim! = 0)
* _MYOSTR << _mydelim;
Return (* this);
}
This overloaded code calls "<<" operator function. In other words, the COPY function has not been expected, and there must be some other questions we have not noticed. I think about it carefully. I think this problem can be explained using C about template, overloading, and type implicit conversion order.
First, the tracking of the program indicates that Ocerator_iterator's Operator = When the "<<" operator is executed, the "<<" operator function in the Basic_OStream class is called:
_MYT & Operator << (const void * _val);
This indicates that the C compiler selects the Const Void * while selecting the parameter type to determine which overload function called, not our own defined const node * &. At this time, I noticed that when we defined our own Operator << function, the parameter P is already const node *, there is no need to add & modifier, the most concise definition method should be: Friend Ostream & Operator << Ostream & O, Const Node * P);
Sure enough, after the previous code is changed to the definition of the pure pointer, the COPY function also shows the number 10, which is the result of our expectation, indicating that the COPY function is correctly called the "<<" operator we overloaded. Why do you simply add a "&" to make the C compiler call another overload function?
I made a simple experiment:
Void foo (Const Int * & P)
{
Cout << "a" << Endl;
}
Void foo (const INT * P)
{
COUT << "b" << endl;
}
int main ()
{
INT i = 10;
INT * P = & I;
Foo (P);
}
The result of this code is A, which means that when the real parameter type is a pointer, the C compiler will prioritize the overload function of the with & modifier (ie, parameter reference type). Is this not the opposite of the situation? The "<< <<" parameter type in the name *, the Basic_OStream class is const void *, and the parameter type we originally overloaded is const node * &, why this time the compiler Don't call our heavy load function? This is not to explain that Node * has been changed after several conversions in a COPY function.
Sure enough, track the running process of the program will find that when COPY calls the OSTREAM_ITERATOR overloaded OPERATOR = function, the real parameter type is node *, and the Operator = function forms parameter type is const_ty &:
ostream_iterator <_ty, _lex, _traits> & operator = (const _ty & _val)
Here, _ty is a template parameter, it is actually the Node * indicated in the COPY function, and the type of parameter becomes:
Node * Const &
The above change can be seen from the debugger of VC.NET. This shows that the OSTREAM_ITERATOR overloaded Operator = function has changed the type of the argument to another (no simple pointer), and then "<<", the compiler will choose Const void * like this. Match, not Const Node * &.
Is it more chaotic? Still consolidation from the head to finish the idea:
First, for the following template function:
Template
When the type of t is the pointer, such as int *, the conjugate of Const and T is int * const, instead of Const Int *, which can be demonstrated by the following code: Template
int main ()
{
INT I;
Const Int * P = & I;
Foo
INT * Const Q = & i;
Foo
}
In C , int * const and const orig * are completely different types, the former const is a modified pointer, the latter const is the value pointed to by the modified pointer.
Second, for such a set of overload functions:
Void foo (const INT * P);
Void foo (int * const p);
When we use the INT * Const type pointer as a real parameter, the compiler selects the second function because the parameter type of the second function is exactly the same. But for such a set of overload functions:
Void foo (const INT * P);
Void foo (const INT * & P);
When we use the INT * Const type pointer as a real parameter, the compiler selects the first function, because the two function parameter types and the type of reference are different, the compiler will call the closest type (parameter) Implicit conversion matching order, you can refer to the description of the C standard).
This is actually the answer to the question we have. The "<<" parameter type in the Basic_OStream class is const void *, and the original user's parameter type is const node * &, and the OPERATOR = function overloaded by ostream_iterator is called "<<" operator, The type has been changed to Node * Const &, so the compiler calls the Ostream_iterator overload function, not our overloaded function.
So, when we modify the "<<" of the most above program to
Friend Ostream & Operator << (Ostream & O, Const Node * P);
When the program can give the correct result. But according to the discussion above, if we change the definition of this function:
Friend Ostream & Operator << (Ostream & O, Node * Const & P);
The program can also give the correct result.
This is just a small problem, and it is accidentally encountered when the friend is programmed. However, this problem is instructions, in the C language, the definition of the parameters, implicit conversion, and matching order are quite important (C standard documentation about this There is a long section of the instructions), I'm easily embraced in these places.