"Assign to Indexed" C++ Operator Overload Brainteaser

c++, operator-overloading

Solution

How about this:

class SampleRef {
  float &left_, &right_;

public:
  SampleRef(float& left, float& right)
    : left_(left), right_(right)
  {}

  operator Sample () {
    return Sample(left_, right_);
  }

  SampleRef& operator= (const Sample &arg) {
    left_ = arg.left;
    right_ = arg.right;
    return *this
  }
};

SampleRef Frames::operator[] (size_t idx) {
  return SampleRef(_leftCh[idx], _rightCh[idx]);
}

You can of course also add a `const` overload of `operator[]` which will simply return a `Sample`:

Sample Frames::operator[] (size_t idx) const {
  return Sample(_leftCh[idx], _rightCh[idx]);
}

Problem

I'm writing some funky audio code and trying to use operator overloading to create a very clean and simple API. It's become of a bit of a C++ brainteaser... What I want would be solved immediately by an "assign to indexed" sort-of-compound operator which I'm pretty sure doesn't exist. Might anyone have any insights on whether the following is possible? I have 2 object types.... ``` Frames frames; // audio data, contains 1 buffer (float *) for each channel Sample s; // a single sample, 1 float for each channel ``` So `Sample` is kind of an orthogonal slice of Frames, ie Frames is NOT an array of `Sample`'s. If you know audio, `Frames` is "non-interleaved", and `Sample` is. The Holy Grail... ``` s = frames[1]; // statement 1. gets a copy of values in frame 1 frames[1] = s; // statement 2. replace values in frame 1 with those in Sample s ``` The first one is no problem: ``` // in class Frames... Sample& operator[](size_t idx) const { Sample s; s.left = _leftCh[idx]; s.right = _rightCh[idx]; return s; } ``` But the second assignment is tricky since the above function creates a copy of the data rather than a reference. I've tried defining Sample with references... ``` class Sample { public: float& L; float& R; Sample(float& lt, float& rt) : L(lt), R(rt) {}; } ``` But then you can't do something as simple as... ``` Sample s(0.0, 0.0); s.left = 0.2; ``` Another potential solution would be to have the two statements call two different operator overloads. Then enforce that statement 2 calls this [] overload which returns a new Frames object pointing to the values rather than a `Sample` object: ``` Frames& operator[](size_t idx) { // Construct an new Frames object whose which // points to value idx in each channel Frames f(_size - idx); f._leftCh = &_leftCh[idx]; f._rightCh = &_rightCh[idx]; return f; } ``` And then add an assignment operator to `Frames` which just replaces the first value... ``` Frames& operator=(const Sample& s) { _leftCh[0] = s.left; _rightCh[0] = s.right; return *this; } ``` The compiler informs me that methods must differ by more than just the return type, but this is resolved by having `const` after the method name for one of the `operator[]` overloads. Might there be a clue here? Is there a way to have statement 1 call `Sample& operator[]...` and statment 2 call `Frames& operator[]...`. Or is there a much better way of accomplishing this?? Thanks for your patience if you've made it this far! Much appreciated...

Original source