3

ファンキーなオーディオコードを作成し、演算子のオーバーロードを使用して非常にクリーンでシンプルなAPIを作成しようとしています。それはちょっとしたC++の頭の体操になりました...

私が望んでいることは、「インデックスに割り当てられた」種類の複合演算子によってすぐに解決されますが、これは存在しないと確信しています。次のことが可能かどうかについて誰かが何か洞察を持っているでしょうか?

2つのオブジェクトタイプがあります。

Frames frames;  // audio data, contains 1 buffer (float *) for each channel
Sample s;       // a single sample, 1 float for each channel

つまりSample、フレームの直交スライスのようなものです。つまり、フレームはの配列ではありませんSample。オーディオを知っている場合Framesは、「非インターリーブ」であり、Sampleです。

聖杯...

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

最初のものは問題ありません:

// in class Frames...
Sample& operator[](size_t idx) const { 
    Sample s;
    s.left = _leftCh[idx];
    s.right = _rightCh[idx];
    return s;
}

ただし、上記の関数は参照ではなくデータのコピーを作成するため、2番目の割り当てには注意が必要です。

参照を使用してサンプルを定義してみました...

class Sample {
public:
    float& L;
    float& R;
    Sample(float& lt, float& rt) : L(lt), R(rt) {};
}

しかし、あなたはそれほど単純なことをすることはできません...

Sample s(0.0, 0.0);
s.left = 0.2;

もう1つの考えられる解決策は、2つのステートメントで2つの異なる演算子のオーバーロードを呼び出すことです。次に、ステートメント2がこの[]オーバーロードを呼び出すように強制します。これにより、オブジェクトではなく値を指す新しいFramesオブジェクトが返されSampleます。

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;
}

Frames次に、最初の値を置き換えるだけの代入演算子を追加します...

Frames& operator=(const Sample& s) {
    _leftCh[0] = s.left;
    _rightCh[0] = s.right;
    return *this;
}

コンパイラは、メソッドは戻り型だけでなく異なる必要があることを通知しますが、これはconst、オーバーロードの1つのメソッド名の後に付けることで解決されoperator[]ます。ここに手がかりがあるのでしょうか?Sample& operator[]...ステートメント1の呼び出しとステートメント2の呼び出しを行う方法はありますかFrames& operator[]...。それとも、これを達成するためのはるかに良い方法がありますか?

あなたがこれまでにそれを成し遂げたならば、あなたの忍耐に感謝します!とても有難い...

4

2 に答える 2

5

これはどう:

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]);
}

constもちろん、オーバーロードを追加することもできます。そのオーバーロードはoperator[]、単に:を返しますSample

Sample Frames::operator[] (size_t idx) const {
  return Sample(_leftCh[idx], _rightCh[idx]);
}
于 2013-03-22T09:24:08.197 に答える
0

詳細を理解するためだけに過負荷をかけずに試しましたか?たとえばsample = frame.getSample(); frame.setSample(sample);、詳細が満足のいくものになったら、構文糖衣を追加して、[]and=演算子をオーバーロードできます。

元のサンプルへの参照を維持したいようです。たとえば、次のようになります。

sample.right = oldR;
sample.left = oldL;
f[x] = sample;

sample.right = newR;
sample.left = newL;
newSample = f[x];

assert(sample.right == newSample.right && sample.left == newSample.left);

これは正しいです?もしそうなら、サンプルを「分割」してフレームに挿入するため、元の接続が失われるため、それはできないと思います。

于 2013-03-22T09:30:03.073 に答える