原本在处理函数模板特化的问题
template <class T>
bool IsEqual(const T& left,const T& right)
{
return left == right;
}
这里我设计了一个模板来判断不同类型的值是否相等,
考虑到节省拷贝时间,同时又不想让函数修改实参,函数的形参设计为常量引用 const T&
。
但是如果面对字符数组,单纯的==
只能比较指针的大小,完全考虑不到字符数组的内容,说明我们的模板覆盖的范围还不够。
所以就字符数组的问题还需特化一个函数模板,其中使用strcmp
函数,用来专门处理C字符串。
我想了下很简单嘛,把T
换成char*
,然后用strcmp
来判断不就行了?
于是写出了字符数组函数模板的特化版本:
//针对字符串类型的特殊化处理--写一份函数模板的特化
template<>
bool IsEqual<char*>(const char*& left,const char* right)//const 修饰的是引用
{
return strcmp(left,right)==0;
}
这里是对指针的常量引用,但是一写完我就觉得怪怪的,果然还没运行,编译器就出现了报错:
一开始我以为是把函数模板特化的格式写错了,但是换了其他的类型之后,发现不是这里的问题。
于是我估计是指针的常量引用写错了,于是做了一小实验看一下,指针的常量引用到底是不是这么写的。
void print1(int*& p)
{
cout << typeid(p).name() << endl;
}
int main()
{
int* a;
print1(a);
}
void print1(const int*& p)
{
cout << typeid(p).name() << endl;
}
int main()
{
int* a;
print1(a);
}
果然,我找到了痛点!!
编译报错了:
error C2664: “void print1(const int *&)”: 无法将参数 1 从“int *”转换为“const int *&”
问题思考:为什么int*
无法转换给const int*&
?
const int*
和 int* const
int main()
{
int b=10;
int* pb=&b;
int *const p0=pb;
const int* p1=pb;
return 0;
}
在常量指针的设计中,const的摆放位置很有讲究,
const
放在*
前,是底层const,“锁”住的是指针指向的值,即该指针无法修改其指向的值。const
放在*
后,是顶层const,“锁”住的是指针本身,即该指针无法修改其自身的值,但是可以修改其自身指向的值。p0 不能修改,但是 *p0 可以修改。
*p1不能修改,但是 p1可以修改。
const int*&
和 int* const&
(重点)const int*&
首先是一个普通引用,而且引用的类型是 const int*
。int* const&
则是常量引用,引用类型是int*
。ok,类型分清楚了,看能不能区分下面p2~p5引用的初始化对错
int main()
{
int b = 10;
int* pb = &b;
int* const p0 = pb;//“锁指针,不锁指向值”
const int* p1 = pb;//“锁指向值,不锁指针”
//区分正误
int* const& p2 = p1;
int* const& p3 = pb;
int* const& p4 = p0;
const int*& p5 = pb;
return 0;
}
p2的情况
p1类型——const int*
p2类型——int* const&
p2是p1的常量引用,始终保证指向p1,而且无法用p2来修改p1的值,这里的值是指针本身。
但是p2有权限可以修改指针指向的值,而p1又锁住了修改指针指向的值的权限,故权限被放大了!p1不会允许p2有这样的越权行为,故错误的初始化❌。
p3的情况
p3和p2的类型一致int* const&
,这里改用pb初始化。pb的类型是int*
pb的类型是int*,p3始终追随pb,而且p3(常量引用)无法修改pb的值。
p3具有修改指向值的权限,pb谁都没锁柱,当然不会越权了。这里是正确的✔
p4的情况
p4依旧是int* const&
类型,这里用类型为int *const
的p0初始化。
p0不能修改自身值,p4是常量引用也无法修改p0的值,恰如其分。
p0可以通过指针修改指向值,p4也可以通过指针修改指向值,恰如其分。
这样就是完全匹配的类型了,是正确的初始化✔。
p5的情况
p5类型——const int*&
pb类型——int*
这里就来到了我们的问题根本。
p5紧紧跟随pb,p5只是普通引用,可以改变pb的指针值,这都ok。
但是! p5指向的值是没有办法修改的,而pb有修改指针指向值的能力
很显然,这样p5的const int*
没有任何意义,调用p5的程序员设想的是:使用的p5指向的是一个无法改变的常量,但是这个“常量”却始终有可能被 *pb 胡乱变动,这不是瞎胡闹吗~
正确处理:
类型完全匹配就可以正常使用引用了。
p1——const int*
p5——const int*&
针对指针的引用:
要么都不能对指向值修改
锁指向值的指针,就用锁指向值的指针的普通引用或锁住指向值的指针的常量引用。
:const int*
和 const int*&
:const int*
和 const int* const &
要么都能对指向值修改
:int*
和 int* &
:int*
和 int* const &
注意⚠:
锁指针值的指针,就必须使用常量引用。
int const*
不能使用 int*&
,这里引用是可以修改锁住的指针的。需使用 int* const&
ok,回到我起初的函数模板特化,