c++operator-overloadingnon-member-functionssubscript-operator

Writing a subscript non-member function


I'm guessing this just isn't legal in C++, but I thought I'd ask, given a struct that I don't own:

struct foo {
    int x;
    int y;
    int z;
};

I want to write a non-member subscript operator for it:

int& operator [](foo& lhs, const std::size_t rhs) {
    switch(rhs) {
    case 0U:
        return lhs.x;
    case 1U:
        return lhs.y;
    case 2U:
        return lhs.z;
    default:
        return *(&(lhs.z) + rhs - 2U);
    }
}

I'm getting this error:

error: int& operator[](foo&, std::size_t) must be a nonstatic member function


Solution

  • struct foo {
        int x;
        int y;
        int z;
    
      int& operator [](const std::size_t rhs) & {
        switch(rhs) {
          case 0U:
            return this->x;
          case 1U:
            return this->y;
          case 2U:
            return this->z;
          default:
            return *(&(this->z) + rhs - 2U);
        }
      }
    };
    

    not all operators can be overloaded as free functions.

    Not the standard, but clearly written over at cppreference, the operators [], =, -> and () must be non-static member functions.

    If you can do wrap(f)[2] you can get it to work. But there is no way to get it to work strait on a foo instance.

    template<class T>
    struct index_wrap_t {
      T t;
      template<class Rhs>
      decltype(auto) operator[](Rhs&& rhs)& {
        return operator_index( *this, std::forward<Rhs>(rhs) );
      }
      template<class Rhs>
      decltype(auto) operator[](Rhs&& rhs)&& {
        return operator_index( std::move(*this), std::forward<Rhs>(rhs) );
      }
      template<class Rhs>
      decltype(auto) operator[](Rhs&& rhs) const& {
        return operator_index( *this, std::forward<Rhs>(rhs) );
      }
      template<class Rhs>
      decltype(auto) operator[](Rhs&& rhs) const&& {
        return operator_index( std::move(*this), std::forward<Rhs>(rhs) );
      }
    };
    
    template<class T>
    index_wrap_t<T> index( T&& t ) { return {std::forward<T>(t)}; }
    

    then you can do this:

    int& operator_index( foo& lhs, std::size_t rhs ) {
      // your body goes here
    }
    foo f;
    index(f)[1] = 2;
    

    and it works.

    index_wrap_t forwards [] to a free call to operator_index that does ADL.