问题简述
编译器提示
今天在增加了一个对employee对象的排序功能以后,遇到了如下问题,所用编译器为VS2015:
错误 C2664 “bool (const employee *&,const employee *&)”: 无法将参数 2 从“employee *”转换为“const employee *&”
错误 C2664 “bool (const employee *&,const employee *&)”: 无法将参数 1 从“employee *”转换为“const employee *&”
相关代码
其错误定在xutility的809行上,查看对应代码,可以发现这段代码是用于检测严格弱序的
// TEMPLATE FUNCTION _Debug_lt_pred
template
inline
_CONST_FUN bool _Debug_lt_pred(_Pr _Pred,
_Ty1&& _Left, _Ty2&& _Right,
_Dbfile_t _File, _Dbline_t _Line)
_NOEXCEPT_OP(_NOEXCEPT_OP(!_Pred(_Left, _Right))
&& _NOEXCEPT_OP(_Pred(_Right, _Left)))
{ // test if _Pred(_Left, _Right) and _Pred is strict weak ordering
return (!_Pred(_Left, _Right)
? false
: _Pred(_Right, _Left)
? (_DEBUG_ERROR2("invalid comparator", _File, _Line), true)
: true);
}
而本程序中涉及严格弱序的函数只有一个,迅速定位到相关代码如下
此为出问题的函数
bool sortPtrNo(const employee *&emp1, const employee *&emp2)
{
return emp1->individualEmpNo < emp2->individualEmpNo;
}
此为引用该谓词的代码,其中empptrList是list<employee *>类型的对象
empptrList.sort(sortPtrNo);
问题解决
在网上发现有人遇到类似问题: 关于C++中const指针引用的转换问题
其中有人分析原因const employee *&中const修饰符修饰employee还是修饰&不明确,具体行为取决于编译器。VS2015将其解释为对employee的修饰,而编译器对于非常量引用要求类型完全一样,而const employee *与employee *的类型显然不一样。将const employee *&改为employee *const &即不报错,此时引用的类型与传入的类型均为employee *。但是本程序中除了指针本身的值不想被改动外,指针所指向的值也不想被改动,于是将其改为const employee *const &即可。因为此时明确告诉编译器const修饰&,而对于常量引用仅需引用的对象能转换成被引用的类型即可,而employee *显然可以转换为const employee *。
const修饰符的探讨
const分为两种,即顶层const和底层const。顶层const指的是对象本身不可改变,显然所有对象均有顶层const,所以声明整型、浮点型的const修饰符均为顶层const。底层const则指所指对象不可改变,指针和引用都有底层const,其中由于引用一旦初始化后不可改变,所以修饰引用的均为底层引用。对于指针来说employee const*是顶层const,而const employee *为底层const。常量引用则更复杂些,其可以看作先利用要绑定的值初始化一个常量类型,再将引用绑定到这个临时对象上。(这句话存疑,如果绑定到临时对象后那么原来对象的值是如何和引用的值同步,有待进一步研究)