4

フォレスト クラスで + 演算子をオーバーロードしようとしています。フォレストは木のコレクションであり、+ 演算子は 2 つのフォレストを 1 つに結合することになっています。クラス定義として次のコードがあります。

template<typename NODETYPE>
class Forest
{


    public:

        friend Forest& operator+<>(Forest&, Forest&);
        friend ostream& operator<<<>(ostream&, const Forest&);
        friend istream& operator>><>(istream&, Forest&);
        Forest();
        Forest( const Forest& otherForest);
        ~Forest();
        void nodes(int&) const;

    private:
        ForestNode<NODETYPE> *root;

        ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};

以下は私の operator+ の実装です:

template<typename NODETYPE>
Forest& operator+<>(Forest& f1, Forest& f2)
{
    f3 = new Forest();
    f3.root = *f1.*root;
    f3.root.sibling = *f2.*root;
    *f1.root = 0;
    *f2.root = 0;
    return f3;
}

コンパイル時に次のエラーが発生します。

|28|エラー: '&' トークンの前にコンストラクタ、デストラクタ、または型変換が必要です|

行 28 は、私の operator+ 実装の署名を参照しています。

私はそれを修正するために、戻り値の型に追加することになっていると思います:

template<typename NODETYPE>
Forest<NODETYPE>& operator+<>(Forest& f1, Forest& f2)
{
    f3 = new Forest();
    f3.root = *f1.*root;
    f3.root.sibling = *f2.*root;
    *f1.root = 0;
    *f2.root = 0;
    return f3;
}

しかし、それは私に次のエラーを与えます:

|28|エラー: 'operator+' を非関数として宣言| |28|エラー: '&' トークンの前にテンプレート引数がありません| |28|エラー: 'f1' はこのスコープで宣言されていません| |28|エラー: '&' トークンの前にテンプレート引数がありません| |28|エラー: 'f2' はこのスコープで宣言されていません|

誰でもこれで私を助けることができますか?とても感謝しています。

4

4 に答える 4

6

operator+ を書くための鍵は、operator+ を書かないことです。 代わりに、コピー ctor と operator+= を記述します。

template<class NodeType>
struct Forest {
  //...
  Forest(Forest const &other);
  //...
  Forest& operator+=(Forest const &other) {
    // code here
    return *this;
  }
  //...
};

次に、演算子 + を追加します。

template<class NodeType>
struct Forest {
  //...
  friend Forest operator+(Forest a, Forest const &b) {
    a += b;
    return a;
  }
  //...
};

以上です!コピーは通常簡単で (許可されないこともあります)、+ よりも += の観点から考える方が簡単かもしれません (2 つのオブジェクトから 3 つ目のオブジェクトを作成するよりも、2 つのオブジェクトがあり、1 つを変更します)。op+ のこのパターンは、同様の型で機能し、-、*、/ などの同様の演算子でも機能します。

于 2010-10-27T10:59:06.733 に答える
3

演算子のオーバーロードは、良いことでも悪いことでもあります。見た目がシンプルなコードにつながる場合に適しています。ライターが誤ったセマンティクスでオーバーロードする場合(ただし、コンパイルするソリューション)、または演算子を直感的に使用する方法でコードが非常に非効率になる場合は、問題があります。

後者のステートメントはstd::stringにも適用できることに注意してください。これにより、大量のコピーが作成される可能性があります。そのため、C ++ 03標準では、文字列を連続したバッファ(昔、彼らはコピーオンライト参照を使用し、必要になるまで連結された両方の文字列へのそのような参照を保存できました。その後、スレッドセーフではないことが判明し、単にバッファをコピーするよりもコストがかかるため、今ではすべてをコピーします。時間と再び非効率的です)。

(スレッド化とアトミックの問題を認識するC ++ 11標準では、読み取り操作を安全にするために、基になるものが連続していてnullで終了している必要があることに注意してください)。

operator +の正しい署名(すべてが同じタイプの場合)は次のとおりです。

T operator+( const T&, const T& );

メンバー関数としては、次のようになります。

class T
{
    // make public if necessary
    T operator+( const T& rhs ) const;
};

演算子+=が使用可能な場合はいつでも、operator+をテンプレートとして自動的に実装できます。

template<typename T, typename R>
T operator+( const T& lhs, const R& rhs )
{
    T copy(lhs);
    return copy += rhs;
}

テンプレートのオーバーロードされた演算子をフレンドとして宣言する場合は、これが正しい方法です。演算子<<で表示します

// first some forward declarations, assume ostream already declared with #include <iosfwd> minimum
template< typename T > class Forest;
template< typename T > std::ostream & operator<<( std::ostream & os, const Forest<T> & for );

template< typename T> class Forest
{
     friend std::ostream& operator<< <>( std::ostream&, const Forest<T> & );
     //rest of class Forest
};

template< typename T >
std::ostream & operator<<( std::ostream& os, const Forest<T> & forest )
{
    // implement
    return os;
}

クラスの友達として宣言したい他の外部関数にも同様の手法を適用します。

  1. クラスをテンプレートとして前方に宣言する
  2. メソッドをテンプレート関数として前方に宣言する
  3. パラメータを示す開き括弧の前に<>を使用して、関数をフレンドにします
  4. クラスの後に関数を実装します。
于 2010-10-27T11:09:26.663 に答える
2

すべてのForestパラメーターにテンプレート引数を指定する必要があります。

template<typename NODETYPE>
Forest<NODETYPE> operator+(Forest<NODETYPE>& f1, Forest<NODETYPE>& f2)

また、引数をconst参照にして、それらを操作しないようにすることを検討してください。

フレンド関数テンプレートに関するスタックオーバーフローに関する質問いくつかあります。 C++ FAQにもいくつかの基本事項を説明するページがあります。

于 2010-10-27T10:38:01.060 に答える
-1

operator+テンプレートは次のように定義できます。

template< class NodeType >
Forest<NodeType> operator+( Forest<NodeType> const& f1, Forest<NodeType> const& f2)
{
    // Implementation.
}

乾杯&hth。、

于 2010-10-27T10:46:59.583 に答える