1

行列を使用するプロジェクトに取り組んでおり、オーバーロードされた演算子に問題があります。

これらの使いやすい入出力関数を宣言しました。

friend std::istream& operator>>(std::istream& is, MathMatrix& m); //keyboard input
friend std::ostream& operator<<(std::ostream& os, const MathMatrix& m); // screen output
friend std::ifstream& operator>>(std::ifstream& ifs, MathMatrix& m); // file input
friend std::ofstream& operator<<(std::ofstream& ofs, const MathMatrix& m); // file output

最後の 1 つを定義しているときに、この単純なコードでエラーが発生し、コンパイルできません。

// file output
std::ofstream& operator<<(std::ofstream& ofs, const MathMatrix& m) {
    //put matrix dimension in first line
    ofs << m.n << std::endl;
    //put data in third line
    for (int i=0; i<m.n; i++) {
        for (int j=0; j<m.n; j++) ofs << m(i,j) << " ";
        ofs << std::endl;
    }
    return ofs;
}

エラーは にありofs << m.nます (および同様のものは にありofs << m(i,j)ます)。それは言います:

const MathMatrix &m
Error: more than one operator "<<" matches these operands:
    function "operator<<(std::ofstream &ofs, const MathMatrix &m)"
    function "std::basic_ostream<_Elem, _Traits>::operator<<(int _Val) [with _Elem=char, _Traits=std::char_traits<char>]"
    operand types are std::ofstream << const int

しばらくして、おそらく問題は のMathMatrixようなコンストラクターがあることにあるのではないかと考えたMathMatrix (int n)ので、コンパイラーは から に変換しようとしている可能性がありint nますMathMatrix(int n)。なぜそうするのかわかりませんが、IDE が提供する説明を考えると、それが私が考えることができる唯一の説明です。

私が欠けているものを見ることができますか?それを修正する方法を知っていますか?

4

2 に答える 2

2

クラスに、クラスとは異なる型の単一の引数を持つコンストラクターがある場合、それを暗黙的な型変換に使用できます。それを防ぐには、そのコンストラクターを明示的にマークする必要があります。

class MathMatrix {
public:
   explicit MathMatrix( int m );
...
};

単一の引数コンストラクターを常に明示的にマークすることをお勧めします (引数が同じクラス型であるか、そのような型変換が必要な場合を除きます)。

于 2013-10-17T18:02:24.760 に答える
2

オーバーロードの解決には微妙な点があり、 call の関数の選択の間にあいまいさが生じますofs << m.n。問題を再現する短い例を次に示します。

struct Base
{
    void operator<<(int);
};

struct Derived : Base
{
};

struct converter
{
    converter(int);
};

void operator<<(Derived&, converter const&);

int main()
{
    const int i = 42;
    Derived d;
    d << i;
}

呼び出しがあいまいであるのはなぜですか?

まず、メンバー関数は、オーバーロード解決のためだけに [over.match.funcs]/2Base::operator<<型の追加パラメーターを取得します。Base&

候補関数のセットには、同じ引数リストに対して解決されるメンバー関数と非メンバー関数の両方を含めることができます。引数とパラメーターのリストがこの異種セット内で比較できるように、メンバー関数は、メンバー関数が呼び出されたオブジェクトを表す暗黙的なオブジェクト パラメーターと呼ばれる追加のパラメーターを持つと見なされます。

メンバー関数 ( で継承されている場合でもDerived) は のメンバー関数であるBaseため、パラメーターの型はBase&ではなくDerived; です。/4 を参照してください。

したがって、比較します

void operator<<(Base&, int);                  // #0
void operator<<(Derived&, converter const&);  // #1

呼び出しの引数はd << i(Derived左辺値) およびconst int. したがって:

  1. オーバーロード用 #0
    1. 最初の引数では、派生からベースへの変換が必要です
    2. 2 番目の引数については、修飾変換が必要です ( const intto int)
  2. オーバーロード用 #1
    1. 最初の引数の完全一致 (変換なし)
    2. 2 番目の引数については、修飾変換とそれに続くユーザー定義の変換が必要です ( const intto intintto converter)

変換 1.1 は変換 2.1 よりも悪いですが、変換 1.2 は変換 2.2 よりも優れています。したがって、呼び出しはあいまいです。


あいまいさを解決する方法は?

また:

  • (推奨) 変換をMathMatrix明示的に行う
  • のみを宣言しoperator<<(std::ostream&, MathMatrix const&)、 for は宣言しませんstd::ofstream(これにより 1.1 が 1.2 に等しくなるため、オーバーロード #1 がより適切に一致します)
  • std::ofstream呼び出し内を明示的に基本クラスに変換しstd::ostreamます (以前のバージョンと同様の方法で役立ちます)
  • たとえば、 using宣言を介して、問題のあるオーバーロードを非表示にします using std::operator<<;
于 2013-10-17T18:34:17.123 に答える