6

私は私を混乱させることにいくつかの問題があります。std::vector独自のクラスを含むa を typedef しました。

typedef std::vector<data::WayPoint> TWayPointList;

DataHandlerこれは、一部の名前空間に抵抗する構造内のネストされた型dataです。

そこで、ベクトルの単一の内容を出力したいと思います。このために、私の考えは、<< 演算子をオーバーロードし、typedef されたベクトルの単一要素をループすることでした。そこで、構造体内で次の出力演算子を宣言しましたDataHandler

namespace data
{
    structure DataHandler
    {

        // ... some code
        typedef std::vector<data::WayPoint> TWayPointList;

        // ... some more code

        /**
         * @brief Globally overloaded output operator
         *
         * @param[in] arOutputStream Reference to output stream.
         * @param[in] arWayPointList WayPoint which should be printed to output stream.
         */
         LIB_EXPORTS friend std::ostream& operator<<(std::ostream& arOutputStream, const data::DataHandler::TWayPointList& arWayPointList);
    } // structure DataHandler
} // namespace data

そして、それぞれのソースファイルでそれを定義しました:

namespace data
{
   std::ostream& operator<<(std::ostream& arOutputStream, const DataHandler::TWayPointList& arWayPointList)
    {
        for(DataHandler::TWayPointList::const_iterator lIterator = arWayPointList.begin(); lIterator < arWayPointList.end(); ++lIterator)
        {
            arOutputStream << *lIterator << std::endl;
        }

        return arOutputStream;
    }
} // namespace data

これはうまくコンパイルされます。しかし、私がこのようなものを追加すると

int main(int argc, char *argv[])
{
    // create Waypoint
    data::WayPoint lWayPoint;

    // create waypoint list
    data::DataHandler::TWayPointList lWayPointList;

    // append two elements
    lWayPointList.push_back(lWayPoint);
    lWayPointList.push_back(lWayPoint);

    std::cout << lWayPointList << std::endl;

    return 0;
}

私のtestmain.cppでは、コンパイラは正しいものを見つけることができなかったと述べていますoperator<<(そして、他のクラスで定義された私自身のいくつかを含む、見つけた多くの仮定を行います)。このようないくつかのエラー

src/main.cpp:107: error: no match for 'operator<<' in 'std::cout << lWayPointList'
src/main.cpp:107:18: note: candidates are:
... a long list of canditates...

ADLと関係があると思いますが、要点がわかりませんでした。

では、コードを機能させるためのアイデアやアドバイスはありますか?

[編集] 明確にするために、ソース コードとエラー出力にいくつかのファイルを追加しました。

4

2 に答える 2

6

フレンド宣言は、そのフレンド宣言を持つクラスの名前空間内の名前空間レベルで関数を宣言します。演算子の定義から、グローバル名前空間で定義しているように見えます(ちなみに、フレンド宣言のコメントにあるように、コンパイラがコメントを読み取らないのは残念です)。operator<<を正しい名前空間で定義する必要があります。

std::ostream& mkilib::operator<<(std::ostream& arOutputStream,
            /*^^^^^^^^*/         const mkilib::DataHandler::TWayPointList& arWayPointList)

または代わりに:

namespace mkilib {
    std::ostream& operator<<(std::ostream& arOutputStream,
                             const DataHandler::TWayPointList& arWayPointList) {...}
}

あなたのプログラムでoperator<<は、オブジェクトを受け取る宣言が 2 つありました。1TWayPointListつはグローバル名前空間 (定義は自己宣言です) に、もう 1 つは::mkilib名前空間に (フレンド宣言から) あります。引数依存のルックアップは で 1 つを見つけていました::mkilibが、それはコードで定義されていませんでした。


更新後、コンパイラはオーバーロードを見つけることができないため、これは実際には問題ではないようです (上記の回答は、コンパイルされたがリンクされていないコードに関するものでした)。名前空間に関して、コードから変更したものがあります。Waypointoperator<<を取る がstd::vector<Waypoint>同じ名前空間で定義されている場合、ADL は正しいオーバーロードを見つけます。が定義されている名前空間にDataHandlerは何の効果もないことに注意してください。


実際、今考えてみると、元の答えが当てはまります。DataHandlerADL はその演算子を検索して内部を検索しないため、friend 宣言はルックアップに影響を与えません。そのため、唯一の宣言operator<<は定義内の自己宣言です。

フレンド宣言は名前空間レベルでエンティティを宣言しますが、宣言はフレンド宣言を持つクラス内でのみ表示されることに注意してください。

アドバイス: ディレクティブの使用は避けてください。混乱と苦痛をもたらすだけです。必要に応じて、名前空間を再度開くか、識別子を修飾します...ディレクティブを使用すると、ルックアップに関する推論がはるかに複雑になります。

于 2012-10-09T20:23:40.423 に答える
1

あなたのコードスニペットからわかるように、あなたはそうではありませんusing namespace dataが、オペレーターはdata名前空間で定義されています。名前空間を使用することもできdataますが、独自の理由があると確信しています。

データ型に固有の演算子を宣言する代わりに、次のように名前空間の外で汎用演算子を定義できます。

template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& list)
{
    for(std::vector<T>::const_iterator iter = list.begin(); iter != list.end(); ++iter)
    {
        out << *iter;
    }
}
于 2012-10-09T20:54:37.510 に答える