4

Following this post I implemented an accessor like

template<class T> class qv {
  virtual const T& operator[](int i) const = 0;
  T& operator[](int i) { return const_cast<T&>(static_cast<const qv*>(this)->operator[](i)); }
};
template<class T> class qq : public qv<T> {
 public:
  const T& operator[](int i) const override { return this->data[i]; }
 protected:
  T data[5];
};

but get an assignment of read-only location when trying to do something like:

int main(int argc, char** argv) {
  qq<int> q;
  q[3] = 2; // read-only location compile error, g++ 6.3
}

It's something with the inheritance that's causing issues but I don't know what or why. As an aside does it matter if I use a static or const_cast for the inner cast above?

user2183336
  • 569
  • 3
  • 13
  • Is `f` a `const` object? Then the `const` qualified `get` function will always be called. Please create a [Minimal, **Complete**, and **Verifiable** Example](http://stackoverflow.com/help/mcve) to show us. – Some programmer dude May 09 '18 at 02:38

1 Answers1

7

The operator[] declared in derived class hides the one in the base class. So qv<T>::operator[] can't be found in name lookup.

(emphasis mine)

name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.

You could add using qv<T>::operator[]; to introduce the name operator[] into the derived class. e.g.

template<class T> class qq : public qv<T> {
 public:
  using qv<T>::operator[];
  const T& operator[](int i) const override { return this->data[i]; }
 protected:
  T data[5];
};

BTW: I suppose that it's a typo to declare qv<T>::operator[] as private.

songyuanyao
  • 147,421
  • 15
  • 261
  • 354
  • interesting. the feature of hiding the non-const version with a const version explicitly overriding seems pretty silly. don't know who would want that. oh well. – user2183336 May 09 '18 at 03:01
  • 1
    @user2183336 it is really no different from any other hiding. A single **name** introduced in derived class hides all **names** in the base class but the one introduced. – SergeyA May 09 '18 at 03:09
  • @user2183336 It's just how name lookup rule works. Answer edited. – songyuanyao May 09 '18 at 03:16