2

私は Visual Studio 2008 で C++ プログラミングの課題に取り組んでいます。次の名前空間階層を定義するファイルが提供されました (名前はこの投稿のためのものです。「名前空間 XYZ-NAMESPACE」は冗長であることはわかっています)。

(MAIN-NAMESPACE){

      a bunch of functions/classes I need to implement...

      (EXCEPTIONS-NAMESPACE){

            a bunch of exceptions
      }

      (POINTER-COLLECTIONS-NAMESPACE){

            Set and LinkedList classes, plus iterators
      }
}

MAIN-NAMESPACE の内容は多数のファイルに分割されており、何らかの理由で、Set と LinkedList の両方の operator<< が完全に MAIN-NAMESPACE の外側にある (ただし、Set と LinkedList のヘッダー ファイル内にある) ことがわかりません。セットバージョンは次のとおりです。

template<typename T>
std::ostream& operator<<(std::ostream& os, 
                         const MAIN-NAMESPACE::POINTER-COLLECTIONS-NAMESPACE::Set<T>& set)

ここに問題があります。次のデータ構造があります。

Set A
Set B
Set C
double num

MAIN-NAMESPACE 内のクラスにあるように定義されています。クラスのインスタンスを作成し、セットの 1 つを出力しようとすると、「エラー C2679: バイナリ '<<' : タイプ 'const MAIN-NAMESPACE: :POINTER-COLLECTIONS-NAMESPACE::Set' (または受け入れ可能な変換がない)

ただし、main() 関数を作成し、セット A を作成し、それを埋めて、演算子を使用すると、機能します。

何が問題なのですか?(注:思いつく限り、using と include の任意の組み合わせを試しました)。

4

8 に答える 8

3

OK、私はこれを理解しました。名前空間に別の operator<< が存在するという jpalecek の直感は正しかった (どうやらコメントアウトするのを忘れていたようだ)。

名前空間のルックアップ ルールは、最初に関数呼び出しの名前空間で検索を開始し、囲んでいる名前空間をグローバル名前空間まで検索します (一致が見つからない場合は、引数に依存するルックアップを実行します)。ただし、途中で operator<< に一致するものが見つかった場合は、ここでのケースのように、それらの関数で使用される型に互換性がない可能性があるという事実に関係なく、検索を停止します。

解決策は、それを MAIN-NAMESPACE に含めるか (許可されていません)、「using ::operator<<」を使用してグローバル名前空間からインポートすることです。

于 2009-01-30T13:38:47.277 に答える
3

奇妙な - 型に関連付けられたフリー関数を別の名前空間に配置することは悪い習慣ですが、グローバル名前空間宣言は常に表示されます。

私が考えることができる唯一のことは、同じ名前の宣言がMAIN-NAMESPACEグローバル名前空間の宣言を覆い隠すということです-operator<<おそらくまったく関係のない型の に はありMAIN-NAMESPACEませんか?その場合は、 でusing ::operator<<宣言して修正する必要がありますMAIN-NAMESPACE。例:

namespace A
{
namespace B
{
  class C{};
}

}

void f(A::B::C*);

namespace A
{
  void f(int*); // try commenting
  using ::f; // these two lines
  void g()
  {
    B::C* c;
    f(c);
  }
}
于 2009-01-30T00:48:27.987 に答える
0

関数を明示的に呼び出してみますか?

::operator<<( cout, myObj );

はい、それはうまくいきます!

現在の名前空間 (呼び出しの場所) または c1 および c2 型の外側の名前空間 (namespace1、namespace2::namespace3) で f 関数を見つけようとしますが、検索で他の名前空間を試行しません。

それでは、これが正しいかどうか見てみましょう: main() 関数から operator<< を呼び出す理由は、(operator<< のように) グローバル名前空間にいたためです。私が実装したクラスから呼び出すときに失敗した理由は、クラスがグローバルでない名前空間にあり、コンパイラをグローバル名前空間に向ける変数がそこになかったためです。

于 2009-01-30T00:50:31.260 に答える
0

関数を明示的に呼び出してみますか?

::operator<<( cout, myObj );
于 2009-01-30T00:23:32.187 に答える
0

SoaBox が指摘したように、明示的に呼び出してみてください。

参考までに、現在の名前空間に隠されているグローバル関数を呼び出したい場合は、関数の前に :: を付けてローカル関数をバイパスし、グローバル関数を呼び出します。

于 2009-01-30T00:31:42.670 に答える
0

訂正: 以下のテキストは、コンパイラの g++ ファミリーでの経験に基づいています。回答へのコメントの後、標準を読み直しました(通常の名前検索ではADLが使用され、通常の名前検索では演算子<<が見つかるはずであると述べています)。私はまた、comeauコンパイラー (私が知っている最も標準に準拠したコンパイラー) を試してみましたが、シンボルが見つかりました。g++ の問題のようです (バージョン 3.3、4.1、4.3 を試しました)。

元の答え:

Koening ルックアップ (技術的には ADL: 引数依存ルックアップ) を検索します。

簡単な答えは、次のクラスがある場合です。

namespace test {
    class A {};
}

ストリーム挿入演算子は次のように定義する必要があります。

namespace test {
    std::ostream& operator<<( std::ostream&, A const & );
}

関数または演算子は、引数の 1 つと同じ名前空間で定義する必要があります。(*)

コンパイラが次のような関数呼び出しを検出した場合:

namespace test2 {
   void g() {
      namespace1::class1 c1;
      namespace2::namespace3::class2 c2;
      f( c1, c2 );
   }
}

現在の名前空間 (呼び出しの場所) または c1 および c2 型の外側の名前空間 (namespace1、namespace2::namespace3) でf関数を見つけようとしますが、検索で他の名前空間を試行しません。

(*) この場合、std 名前空間 (テンプレートの特殊化のみ) に関数を追加することは許可されていないため、 test名前空間にほとんど制限されます。

元の投稿の終わり

前にコメントしたように、これがコンパイラの問題である可能性がある場合でも、一般的な使用法であり、型自体と同じ名前空間でユーザー定義型を操作するすべてのフリー関数を定義することをお勧めします。

于 2009-01-30T00:39:13.793 に答える
0

OK の人々が特定の例を求めたので、ここにコードの関連部分を示します。//免責事項: 私の大学の誰かがこれを見て、提出ファイルでそれを見つけ、私がそれをコピーしたか何かであると判断した場合、私の学生番号は 311670137 です

これはヘッダー ファイル Set.h です。

   namespace MTM {//This is the MAIN-NAMESPACE

    namespace PointerCollections {

        (ITERATORS AND PREDICATE CLASSES)

        template<typename T>
        class Set {
        public:

        /////////////////////////////////
        // Definitions
        /////////////////////////////////

        private:

        /////////////////////////////////
        // Definitions
        /////////////////////////////////

        };


///////////////////////////////////////////////////////////////////////////////
// The implementation part. 
///////////////////////////////////////////////////////////////////////////////
      }
}
// operator<< - the same a Set::print(std::ostream& os,
//                                    const BinaryPredicate<T>& predicate) 
// function called with the 'predicate' parameter omitted
template<typename T>
std::ostream& operator<<(std::ostream& os, 
                         const MTM::PointerCollections::Set<T>& set){

    set.print(os);
    return os;
}

これは、別のファイルで定義したものです。

namespace MTM {
    using std::ostream;

    class Schedule {
    public:
      ///////////////////
      //Definitions, including: 
      ///////////////////
    void registerStation(string stationName);
    void reportRegisteredStations(std::ostream& outputStream) const;

    private:     //My database
               //All the classes Set recieves are defined elsewhere
        Set<RegisteredStation> places;
        Set<BusLine> busses;
        Set<TrainLine> trains;
        double tarifForBuses;
        double tarifForTrains;
    };

}

そして、これがメインからです:

Schedule s();
s.registerStation("1");
s.reportRegisteredStations(cout);//This invokes the error. Definition follows:

reportRegisteredStations は次のように定義されます。

void Schedule::reportRegisteredStations(std::ostream& outputStream) const{

        outputStream<<places;
    }
于 2009-01-30T01:07:20.337 に答える
0

これは私のために働く

#include <iostream>
#include <string>
using std::string;

   namespace MTM {//This is the MAIN-NAMESPACE

    namespace PointerCollections {

        template<typename T>
        class Set {
        };


      }
}
template<typename T>
std::ostream& operator<<(std::ostream& os, 
                         const MTM::PointerCollections::Set<T>& set){

    return os;
}

namespace MTM {
    using std::ostream;
  using PointerCollections::Set;
    class Schedule {
    public:
      ///////////////////
      //Definitions, including: 
      ///////////////////
    void registerStation(string stationName);
    void reportRegisteredStations(std::ostream& outputStream) const;

    private:     //My database
               //All the classes Set recieves are defined elsewhere
        Set<int> places;
        Set<int> busses;
        Set<int> trains;
        double tarifForBuses;
        double tarifForTrains;
    };
void Schedule::reportRegisteredStations(std::ostream& outputStream) const{

        outputStream<<places;
    }

}

int main()
{
  MTM::Schedule s;
  s.reportRegisteredStations(std::cout);
}
于 2009-01-30T01:26:55.743 に答える