2013-07-30 14 views
11

次のコードが壊れています。コード内の特定の行を修正することで修正できます(コメント参照)。問題の原因は何ですか?演算子の戻り値++

#include <iostream> 
using namespace std; 

class Number{ 
public: 
    int n; 
    Number(int a):n(a){} 

    //when I change the following to 
    //friend Number& operator++(Number& source, int i) 
    //then it compiles fine and correct value is printed 
    friend Number operator++(Number& source, int i){ 
     ++source.n; 
     return source; 
    } 
}; 

int main() { 

    Number x(5); 
    x++++; //error: no 'operator++(int)' declared for postfix '++' [-fpermissive] 
    cout<<x.n; 

    return 0; 
} 
+1

なぜこれはあなたを驚かせるのですか?後置される 'operator ++'の意味、あなたが何を返そうとしているのか、あなたが何をしようとしているのか、誰にやっているのかを考えてみましょう。 –

+0

なぜあなたのコードに 'friend'が必要ですか? – triclosan

+0

@triclosanここでは必要ないが、彼はプライベートメンバーを持っていて、メンバーの過負荷とは対照的なグローバルな機能を望んでいると仮定していますか? –

答えて

16

あなたは最初の呼び出しによって返された一時オブジェクトに2つ目の++を適用しよう。ただし、オペランドは参照渡しする必要があります。また、一時的でないものを左辺参照にバインドすることはできません。

そのような一時的な値を変更する理由はほとんどがありますので、あなたはおそらく、これを「修正」する必要はありません。ただし、の値をコピーしてからをインクリメントして、予想されるポストインクリメントの動作を得てください。

接頭演算子は、予想通り++++x;が動作するはずように喜んで別の基準に結合可能な参照を返すべきです。

+0

問題は、postfixの増分*が既にインクリメントされた値! –

+0

@マークB:そうすることはできません。私はコードを正しく読まなかった。 –

+0

なぜ彼は 'operator ++'を 'friend 'とするのですか? –

8

あなたはx++ ++を書き込むことによって、内側operator++の戻り値を増加しています。つまり、その演算子の戻り値が変更可能なものでなければ、コードはコンパイルされません。

Number &の代わりにNumberを返すように宣言すれば、それは変更できません(関数の戻り値は参照でない限り一時的で左辺値ではないため、それを取る外部演算子++ (非const)参照で、valueで返されたオブジェクトにバインドすることはできません)。

+0

クラスの型の一時的な値/右辺値を正しく修正できます。問題は、演算子が非const参照によって最初の引数を取るため、値を返した場合に演算子を連結できないことです。 – jrok

+0

@jrok(私は実際にそのような疑いがありましたが、わかりませんでした)したがって、 "外側の演算子++"(非const参照)を参照すると、バインドできませんそれは値によって返されるオブジェクトに "? –

+0

それはうまくいくと思います。 – jrok

3

あなたがしようとしていることは非常に珍しいことです。ポストインクリメントは、通常インクリメント(最初のオブジェクトをインクリメントした後、左辺値として、そのオブジェクト自体を返し、インクリメントを事前とは対照的に)前にオブジェクトを表す右辺値を返します。基本的には、ポストインクリメントがプリインクリメントと同じように動作するようにしようとしています。

通常、あなたはこのようなものだろう。この定義に

class Number { 
    int n; 
public: 
    // Pre-increment 
    Number& operator++() { 
    ++n; 
    return *this; 
    } 
    Number operator++(int) { 
    Number temp = *this; // capture old value 
    ++(*this); 
    return temp; 
    } 
}; 

を、x++++はコンパイルされません - しかし、xintあるとき、それはまた、コンパイルされません:それは本当に多くのことはありませんセンス。

次のようにとにかく、それはあなたのために動作しない理由があります。 x++++

operator++(operator++(x, 0), 0) 

内側operator++呼び出しが一時的Numberオブジェクトを返すものと解釈されます。外部operator++()は、タイプがNumber&であることを想定していますが、非const参照は一時的にバインドできません。 operator++Number& - 左辺値を返すように宣言を変更すると、この戻り値はoperator++外側の呼び出しにうれしく渡すことができます。

+0

'x.operator ++(0).operator ++(0)'は形式が整っているので、あなたのコードで 'x ++++'は実際にコンパイルされると思います。メンバ 'Number operator ++(int)&'を宣言することでこれを修正することができます(しかし最近のgcc/clangバージョンではそれがサポートされていますが、MicrosoftコンパイラではAFAIKはサポートされていません)。 – aschepler

+0

@Igor Tandetnik ascheplerは正しいです - それはコンパイルします。とにかく、私はポイント、感謝を得る。 – Slazer

0

あなたはどちらかintため、このようなチェーンポストインクリメント演算子ではないことを観察してから始めるのをしてみましょう!

それから、問題が発生する前に、このような直観的ではないコードを書かないように提案しましょう。誰かがあなたのプログラムを1年後に読む必要があり、あなたはそれを可能な限り簡単にしたいと思っています。

operator++(operator++(x, int), int)のようなものだと考えてみましょう。だから、最初のoperator++が値で戻ってきます(その結果、名前のない一時的な結果が返されます)。この名前のないテンポラリは、第2(外側)呼び出しに対する非const参照パラメータにバインドすることはできません。メソッドの参照は失敗します。

最後に、実装は実際には後置インクリメントを実装していないことに注意してください。これは接頭辞インクリメントを実装しています。 intパラメータ(後置を示す)を削除するか、または未修正の値を返すように実装を修正する必要があります。

関連する問題