const T 到const *&T的转换

问题简述


编译器提示

今天在增加了一个对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类型的对象

			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。常量引用则更复杂些,其可以看作先利用要绑定的值初始化一个常量类型,再将引用绑定到这个临时对象上。(这句话存疑,如果绑定到临时对象后那么原来对象的值是如何和引用的值同步,有待进一步研究)

总结

非常量引用要求对象类型严格相同,而常量引用相当于先生成一个临时的常量对象,再将该临时对象绑定到引用上,此时只要绑定对象的类型可以转换为引用的类型即可。为了让程序更清晰,在类型较为复杂时,可以采用类型别名简化类型名。

你可能感兴趣的:(C++)