演算子<<は引数を1つだけ取る必要があります


91

ああ

#include "logic.h"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

私がコンパイルすると、それは言う:

std :: ostream&logic :: operator <<(std :: ostream&、A&) 'は引数を1つだけ取る必要があります。

何が問題ですか?

回答:


127

問題は、それをクラス内で定義することです。

a)は、2番目の引数が暗黙的(this)であり、

b)それはあなたがしたいこと、つまりextendをしませんstd::ostream

あなたはそれを自由関数として定義する必要があります:

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);

8
また、彼はそれをフレンド関数として宣言し、メンバー関数として定義しています。
asaelr 2012年

en.cppreference.com/w/cpp/language/operatorsで述べたように、「演算子>>と演算子<<のオーバーロードは、左側の引数としてstd :: istream&またはstd :: ostream&を受け取り、挿入および抽出演算子。これらはユーザー定義の型を正しい引数(a @ bのb)として受け取るため、非メンバーとして実装する必要があります。
モルテザ

49

フレンド関数はメンバー関数ではないため、問題はoperator<<フレンドとして宣言することですA

 friend ostream& operator<<(ostream&, A&);

次に、それをクラスのメンバー関数として定義してみます logic

 ostream& logic::operator<<(ostream& os, A& a)
          ^^^^^^^

logicクラスなのか名前空間なのか混乱していますか?

エラーは、operator<<2つの引数を取るメンバーを定義しようとしたためです。つまり、暗黙のthisパラメーターを含む3つの引数を取ります。演算子は2つの引数しか取ることができないためa << b、2つの引数を書き込むと、aとになりbます。

あなたostream& operator<<(ostream&, const A&)メンバー関数として定義したいのですlogicが、そのクラスとは何の関係もないので、のメンバーとしては間違いありません!

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}

3

テンプレート化されたクラスでこの問題に遭遇しました。これが私が使用しなければならなかったより一般的な解決策です:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // Friend means operator<< can use private variables
    // It needs to be declared as a template, but T is taken
    template <class U>
    friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}

// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
  obj.toString(os);
  return os;
}

現在:* cppに隠れている場合、私のtoString()関数をインラインにすることはできません。*ヘッダーにコードが残っていて、それを取り除くことができませんでした。*オペレーターはtoString()メソッドを呼び出しますが、インライン化されません。

operator <<の本体は、friend句内またはクラス外で宣言できます。どちらのオプションも醜いです。:(

多分私は何かを誤解している、または見当たらないが、演算子テンプレートを前方宣言するだけではgccにリンクしない。

これも機能します:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // For some reason this requires using T, and not U as above
    friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
    {
        obj.toString(os);
        return os;
    }
}

operator <<を実装するためにテンプレート化されていない親クラスを使用し、仮想toString()メソッドを使用する場合は、ヘッダーの宣言を強制するテンプレートの問題も回避できると思います。


0

operator<<メンバー関数として定義すると、非メンバーを使用した場合とは異なる構文になりますoperator<<。非メンバーoperator<<は2項演算子であり、メンバーoperator<<は単項演算子です。

// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);

struct MyObj
{
    // This is a member unary-operator, hence one argument
    MyObj& operator<<(std::ostream& os) { os << *this; return *this; }

    int value = 8;
};

// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
    return os << myObj.value;
}

それで……本当にどうやってそれらを呼ぶのですか?演算子はいくつかの点で奇妙operator<<(...)です。物事が意味をなすように頭の中に構文を書くように挑戦します。

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

または、非メンバーの2項演算子を呼び出そうとすることもできます。

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

これらの演算子をメンバー関数にしたときに、これらの演算子を直感的に動作させる義務はありません。必要に応じて、operator<<(int)一部のメンバー変数を左シフトするように定義できます。コメントの数に関係なく、人々が少し油断している可能性があることを理解してください。書く。

最後に、オペレーター呼び出しの両方の分解が有効である場合があります。ここで問題が発生した場合は、その会話を延期します。

最後に、2項演算子のように見えるはずの単項メンバー演算子を記述するのがいかに奇妙であるかに注意してください。 )

struct MyObj
{
    // Note that we now return the ostream
    std::ostream& operator<<(std::ostream& os) { os << *this; return os; }

    int value = 8;
};

この構文は、多くのコーダーを苛立たせます...

MyObj mo;

mo << std::cout << "Words words words";

// this decomposes to...
mo.operator<<(std::cout) << "Words words words";

// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");

coutここでチェーンの2番目の引数がどのようになっているかに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.