简化const重载?

tem*_*def 42 c++ overloading const

我已经教了很多年的C++编程课程,向学生解释的最棘手的事情之一是const重载.我通常使用类似矢量的类及其operator[]函数的示例:

template <typename T> class Vector {
public:
    T& operator[] (size_t index);
    const T& operator[] (size_t index) const;
};
Run Code Online (Sandbox Code Playgroud)

我很难解释为什么需要两个版本的operator[]函数,但在试图解释如何将两个实现统一起来时,我常常发现自己浪费了很多时间使用语言arcana.问题是,我知道如何使用const_cast/ static_casttrick 实现其中一个函数的唯一好的,可靠的方法是:/ trick:

template <typename T> const T& Vector<T>::operator[] (size_t index) const {
     /* ... your implementation here ... */
}
template <typename T> T& Vector<T>::operator[] (size_t index) {
    return const_cast<T&>(static_cast<const Vector&>(*this)[index]);
}
Run Code Online (Sandbox Code Playgroud)

这种设置的问题在于解释起来非常棘手,而且根本不明显.当你把它解释为"转换为const,然后调用const版本,然后去掉constness"时,它会更容易理解,但实际的语法是可怕的.解释什么const_cast是,为什么它的适当位置,以及它为什么几乎普遍不恰当的其他地方通常需要我五至十分钟的演讲时间,而这整个表达式的决策意识往往需要比之间的差异更多的精力const T*T* const.我觉得学生需要了解const-overloading以及如何在不必要地复制两个函数中的代码的情况下完成它,但是这个技巧在C++入门编程课程中似乎有些过分.

我的问题是 - 是否有一种更简单的方法来实现相互const重叠的功能?或者是否有更简单的方法向学生解释现有技巧?

Lig*_*ica 12

我通常认为这是一种语言限制,并建议人们 - 除非他们真的知道他们在做什么 - 他们应该重新实现.在绝大多数情况下,这些功能都是简单的单线吸气剂,所以没有痛苦.

在你教授C++的过程中,我对这种方法的态度会更强烈.


Sea*_*ean 8

如何简单地将其分解为更小的步骤?

const Vector<T>& const_this = *this;
const T& const_elem = const_this[index];
T& mutable_elem = const_cast<T&>(const_elem);
return mutable_elem;
Run Code Online (Sandbox Code Playgroud)

您甚至可以通过static_cast这种方式消除这种情况,但如果您认为它更清晰,您可以将其保留.

  • 仅当我们采用最初为const的对象并尝试剥离constness时,这才是未定义的行为。在这种情况下,由于您要调用非const成员,因此可以确保原始对象不是const。因此,迈耶斯把戏。 (2认同)

Rom*_*n L 7

这是一个非常奇怪的选项,但这可以使用像这样的静态模板助手来完成

// template parameters can be const or non-const
template<class Ret, class C>
static Ret& get(C* p, size_t index) { /* common code here like p->array[index] */ }
Run Code Online (Sandbox Code Playgroud)

然后你就可以写了

const T& operator[](size_t index) const { return get<const T>(this, index); }
T& operator[](size_t index) { return get<T>(this, index); }
Run Code Online (Sandbox Code Playgroud)

这个技巧避免了强制转换(!)和双重实现,但是,再次,它看起来很奇怪:)

关于你的代码片段的一个小小的评论,还const_cast不够static_cast,或者我错过了什么?


Mar*_*ork 6

您可以使用私有方法删除一个
强制转换:它添加了一个方法,但使得强制转换不那么复杂:

template <typename T>
class Vector
{
  public:
    T const& operator[](size_t i) const { return getValue(i);}
    T&       operator[](size_t i)       { return const_cast<T&>(getValue(i));}

  private:
    T const& getValue(size_t i) const   { return /* STUFF */;}
};
Run Code Online (Sandbox Code Playgroud)