为什么没有标准化的方法来避免const方法的代码重复
Why is there no standardized way to avoid const method code duplication?
根据我的经验,在成员方法的常量和非常量版本中使用相同的代码是一种常见现象。避免复杂方法代码重复的一种方法是使用const_cast
来删除非常量版本中的常量,如Effective C++(第3项)中推荐的Scott Meyers。然而,这在可能只返回指针的非常短的方法中是没有好处的——当然,在这种情况下,重复并没有那么大的问题。尽管如此,这还是让我怀疑是否有原因没有关键字或类似的东西来代替选角。我可以想象使用以下声明:
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
变体,但不需要重复"处理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 c, int const p)
{ return /* ThisType = HyperMatrix<T> */ at(this, r, c, p); }
const T& operator()(int const r, int const c, int const p)
{ return /* ThisType = const HyperMatrix<T> */ at(this, r, c, 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); }
};
我不满足你的需求。事实上,如果您发现自己反复抛弃const
,那么您的代码一开始就完全正确,我对此并不买账。
考虑一下,您可以将非const
对象传递给期望const
对象的函数。参数上的const
只是一个约定,被调用者不会更改对象——它要么更改,要么不更改。如果它确实改变了它,那么传递const
对象就是一个错误(其错误是有争议的,但在某个地方存在错误)。如果它不改变它,你可以通过任何东西。
我不知道除了尝试用正确的契约重写代码之外,还有什么好说的,或者如果你不介意,干脆不要使用任何const
。
- 如何在声明为 const 的方法中更改类成员
- 具有参数 (const T *&) 或 (T * &) 或 (const T * const &) 或 (T * const &) 的方法
- 从 const 对象访问非 const 方法
- 为什么我可以调用一个从const方法更改成员的方法
- 使用新的c++返回值语法的Const方法
- MSVC使用constexpr-if从可变模板方法中的基本模板参数中吞下const
- const_cast const 方法中的"this"将"this"分配给外部变量?
- 初始化 const 成员的正确方法
- const 方法使用引用修改对象
- 从类方法返回 "const char*" 作为 std::string&
- 从"wcslen"替换到"strnlen_s"时,用"const char*"进行类型转换是正确的方法吗?
- 将const指针(EVP_MD)保存到变量中,以将其重新使用为类方法(HMAC)
- 为什么 constexpr 假设我的方法就是 const
- 正确的方法通过巨大的const对象的向量
- 使用静态方法初始化 const 类字段的做法是好是坏
- 为什么重写方法并将 const 添加到参数类型有效
- CPP主方法const声明
- 如何基于模板参数制作方法const
- 命名重载的getter方法:const和nonconst
- 声明Get方法const时出错