根据我的经验,在const和非const版本的成员方法中使用相同的代码是一种常见的现象.避免复杂方法的代码重复的一种方法是使用const_cast来删除非const版本中的const-ness,如Scott Meyers在Effective C中推荐的那样(第3项).然而,这对于可能只返回指针的非常短的方法是没有益处的 – 当然,在这种情况下复制不是那么有问题.这仍然让我想知道是否有一个原因是没有关键字或类似的东西来取代铸造.
我可以想象使用以下声明:
我可以想象使用以下声明:
autoconst Data* const getData() autoconst;
当然这个关键字不会添加任何以前无法实现的功能,但我认为它会很好.据我所知,auto关键字同样不允许任何新的结构,但在代码中是一个很好的简化 – 不可否认的是更广泛(如果我错了请纠正我).
我的问题是这是否与C标准中的某些规则相冲突 – 如果不是,它是否只是没有用到实施.
解决方法
有一种标准化的方式,但没有多少人使用它:
class X { T data; public: template<typename autoconst> friend /* or static */ auto get_data(autoconst& that) -> decltype(that.data) { // process that and return that.data } };
它被称为get_data(x)而不是x.get_data(),但是一个实现同时提供const和非const用法,没有强制转换或其他非类型安全技术.
还可以使用成员函数来启用成员调用语法.这将需要const和非const变体,但没有重复“process that.data”步骤,因为两者都可以委托给朋友模板.
更完整的例子:
template<typename T> class HyperMatrix { int rows,cols,planes; T* data; /* they get initialized somehow */ public: template<typename ThisType> friend /* or static */ auto at(ThisType& that,int const r,int const c,int const p) -> decltype(*(that.data)) { // argument validation logic not being duplicated if (r < 0 || r >= that.rows) throw index_exception(); if (c < 0 || c >= that.cols) throw index_exception(); if (p < 0 || p >= that.planes) throw index_exception(); // complicated indexing expression,also not duplicated const index = (p * that.rows + r) * that.cols + c; return that.data[index]; } // these enable a more natural Syntax than at(hymatrix,1,2,3) T& operator()(int const r,int const p) { return /* ThisType = HyperMatrix<T> */ at(this,r,c,p); } const T& operator()(int const r,int const p) { return /* ThisType = const HyperMatrix<T> */ at(this,p); } };
示例没有简单的解决方法:
template<typename T> class BalancedJumpTable { public: template<typename ThisType,typename Functor> friend /* or static */ auto for_each(ThisType& that,Functor f) { // complicated code for walking the tree not duplicated // deep inside loops and recursive calls,we find f(that->something()); // maybe there's even some filtering logic which causes only // only certain items to be passed to the callback } template<typename Functor> void for_each(Functor f) { return for_each(this,f); } void for_each(Functor f) const { return for_each(this,f); } };