The topic of this section is to use member templates to accept all compatible types
The author explains his point of view through the example of smart pointers.
Before we learn the terms of this section, we need to understand the problem of implicit transformation.
The following code:
#include<iostream>using namespace std;class A{public: explicitA(int i):a(i){}; A(const A&obj):a(obj.a) { }private: int a;};int main(){ intvalue =0; value;//编译不通过,因为构造函数中有explicit限定符 return0; }
We know that because of the existence of the explicit qualifier the compilation does not pass.
Let's look at the code in another section of the book:
template<typename T> class SmartPrt{ public: explicit SmartPtr(T* realPtr); …… }; SmartPtr<Top> pt1=SmartPtr<Middle>(new Middle); SmartPrt<Top> pt2=SmartPrt<Bottom>(new Bottom); SmartPrt<const Top> pct2=pt1;
我们可以知道,因为`SmartPtr<Top>`类型和`SmartPtr<Middle>`
The
type is different, plus explicit smartptr<middle>
explicit qualifier, smartptr<top> pt1=smartptr< Middle> (new middle);
This code compilation does not pass.
and the compiler does not consider smartptr<top>
type and smartptr<middle>
type has an inheritance relationship.
to be able to achieve mutual transformation, you can add the main thrust of this section to solve the above problems.
The following code:
Template<typaname t> class smartptr{public : Template<typename u> smartprt (const smartprt<u>& Other": heldprt (Other.get ()) {}; t* get () const { return Heldprt;} ...... private : t* heldprt; }; Smartptr<top> pt1=smartptr<middle> (new middle); Smartprt<top> pt2=smartprt<bottom> (new Bottom); Smartprt<const top> pct2=pt1;
We have added a member function template, because TypeName T and TypeName U are two types, and there is no explicit keyword in the constructor and will not block heldPrt(other.get())的隐式转换
. So, the above code can be compiled.
The author concludes by listing an excerpt from the TR1 specification for TR1::SHARED_PTR
As follows:
Template<classT>class shared_ptr{ Public:Template<classY>Explicit shared_ptr(y* p);Template<classY>shared_ptr(shared_ptr<Y>Const& R);Template<classY>Explicit shared_ptr(weak_ptr<y>Const& R);Template<classY>Explicit shared_ptr(auto_ptr<Y>Const& R);Template<classY>shared_ptr&operator=(shared_ptr<Y>Const& R);Template<classY>shared_ptr&operator=(auto_ptr<Y>Const& R); ...... };
We can see that only the generalization copy constructor is not explicit, which means that the implicit conversion of shared_ptr is allowed, while the other smart pointer conversions are not allowed.
There is also a need to be aware that the class declaration of the generalization copy constructor (member template) does not prevent the compiler from generating their own copy constructors (Non-template), in other words, If the program only writes the generalization of the copy constructor, then the compiler will automatically generate a non-generalized version, if you do not want this default version, it must not be lazy, two versions of the copy constructor to write.
The code is as follows:
template<typaname T> class SmartPtr{ public: template<typename U> SmartPrt(const SmartPrt<U>& other) :heldPrt(other.get()){}; SmartPtr(){}//如果不写自己的非泛化构造函数,编译器会自动生成自己的默认非泛化构造函数。 getconst{return heldPrt;} …… private: T* heldPrt; };
At last:
The author concludes as follows:
1. Use member function templates (member function template) to generate "acceptable all compatible types" functions;
2. If you declare member templates for "Generalization copy construction" or "generalization assignment operation", you still need to declare the normal copy constructor and copy assignment operator.
Effective C + + clause 45