257

行列演算用に C++ で小さな行列ライブラリを作成しています。ただし、以前はそうではなかったのに、私のコンパイラは文句を言います。このコードは 6 か月間棚に置かれ、その間にコンピューターを debian etch から lenny (g++ (Debian 4.3.2-1.1) 4.3.2) にアップグレードしましたが、同じ g++ を使用する Ubuntu システムでも同じ問題が発生します。 .

私のマトリックスクラスの関連部分は次のとおりです。

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
    }
}

そして「実装」:

using namespace Math;

std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {

    [...]

}

これは、コンパイラによって表示されるエラーです。

matrix.cpp:459: エラー: 'std::ostream& Math::Matrix::operator<<(std::ostream&, const Math::Matrix&)' は 1 つの引数を取る必要があります

私はこのエラーに少し混乱していますが、6 か月間多くの Java を実行した後、私の C++ は少し錆びてきました。:-)

4

6 に答える 6

147

もう1つの可能性についてお話しします。私はそのために友達の定義を使用するのが好きです。

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
            [...]
        }
    };
}

関数は自動的に周囲の名前空間をターゲットにしますがMath(その定義はそのクラスのスコープ内に表示されます)、引数に依存するルックアップでその演算子定義を検出するMatrixオブジェクトを使用してoperator <<を呼び出さない限り、表示されません。これは、Matrix以外の引数タイプでは表示されないため、あいまいな呼び出しに役立つ場合があります。定義を作成するときに、Matrixで定義された名前と、Matrix自体を直接参照することもできます。名前を長いプレフィックスで修飾したり、のようなテンプレートパラメーターを指定したりする必要はありませんMath::Matrix<TypeA, N>

于 2009-01-24T22:28:38.647 に答える
138

関数を として宣言しましfriendた。クラスのメンバーではありません。Matrix::実装から削除する必要があります。friend指定された関数 (クラスのメンバーではない) がプライベート メンバー変数にアクセスできることを意味します。Matrix関数を実装した方法は、間違っているクラスのインスタンス メソッドのようなものです。

于 2009-01-24T16:37:35.983 に答える
87

Mehrdadの回答に追加するには、

namespace Math
{
    class Matrix
    {
       public:

       [...]


    }   
    std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}

あなたの実装では

std::ostream& operator<<(std::ostream& stream, 
                     const Math::Matrix& matrix) {
    matrix.print(stream); //assuming you define print for matrix 
    return stream;
 }
于 2009-01-24T18:51:16.277 に答える
77

クラスを処理するためにoperator <<派生したすべてのクラスのオーバーロードについて話していると仮定すると(クラスのオーバーロードではありません)、ヘッダーの Math 名前空間の外側でオーバーロード関数を宣言する方が理にかなっています。std::ostreamMatrix<<Matrix

フレンド関数は、パブリック インターフェイスを介して機能を実現できない場合にのみ使用してください。

Matrix.h

namespace Math { 
    class Matrix { 
        //...
    };  
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);

演算子のオーバーロードは名前空間の外で宣言されていることに注意してください。

マトリックス.cpp

using namespace Math;
using namespace std;

ostream& operator<< (ostream& os, const Matrix& obj) {
    os << obj.getXYZ() << obj.getABC() << '\n';
    return os;
}

一方、オーバーロード関数をフレンドにする必要がある場合、つまり、プライベートおよび保護されたメンバーへのアクセスが必要です。

Math.h

namespace Math {
    class Matrix {
        public:
            friend std::ostream& operator<<(std::ostream&, const Matrix&);
    };
}

関数定義は、単に ではなく名前空間ブロックで囲む必要がありますusing namespace Math;

マトリックス.cpp

using namespace Math;
using namespace std;

namespace Math {
    ostream& operator<<(ostream& os, const Matrix& obj) {
        os << obj.XYZ << obj.ABC << '\n';
        return os;
    }                 
}
于 2012-02-10T16:09:49.673 に答える
46

C++14 では、次のテンプレートを使用して、 T::print(std::ostream&)const; を持つ任意のオブジェクトを出力できます。メンバー。

template<class T>
auto operator<<(std::ostream& os, T const & t) -> decltype(t.print(os), os) 
{ 
    t.print(os); 
    return os; 
} 

C++20 ではコンセプトを使用できます。

template<typename T>
concept Printable = requires(std::ostream& os, T const & t) {
    { t.print(os) };
};

template<Printable T>
std::ostream& operator<<(std::ostream& os, const T& t) { 
    t.print(os); 
    return os; 
} 
于 2016-03-05T08:24:36.600 に答える