C++使用typedef'd std :: vector重载<<运算符

nig*_*arc 6 c++ operator-overloading

让我受到欢迎,我遇到了一些问题.我有一个std::vector包含一些自己的类的typedef'ed :

typedef std::vector<data::WayPoint> TWayPointList;
Run Code Online (Sandbox Code Playgroud)

这是结构内部的嵌套类型,DataHandler它在某些命名空间中存在data.

所以,现在我想打印出矢量的单个内容.为此,我的想法是重载<<运算符并循环遍历typedef'ed向量的单个元素.所以我在结构中声明了以下输出操作符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
Run Code Online (Sandbox Code Playgroud)

并在相应的源文件中定义它:

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
Run Code Online (Sandbox Code Playgroud)

编译好了.但是,如果我添加这样的东西

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;
}
Run Code Online (Sandbox Code Playgroud)

在我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...
Run Code Online (Sandbox Code Playgroud)

我认为它与ADL有关,但我没有明白这一点.

那么,任何想法和想法让代码工作?

[edit]我在源代码和错误输出中添加了一些文件以便澄清.

Dav*_*eas 6

friend声明在具有此类friend声明的类的名称空间中声明了名称空间级别的函数.从运算符的定义来看,你似乎是在全局命名空间中定义它(顺便提一下你在朋友声明中的评论所说的,太糟糕的编译器不会读取注释).您需要operator<<在正确的命名空间中定义:

std::ostream& mkilib::operator<<(std::ostream& arOutputStream,
            /*^^^^^^^^*/         const mkilib::DataHandler::TWayPointList& arWayPointList)
Run Code Online (Sandbox Code Playgroud)

或者:

namespace mkilib {
    std::ostream& operator<<(std::ostream& arOutputStream,
                             const DataHandler::TWayPointList& arWayPointList) {...}
}
Run Code Online (Sandbox Code Playgroud)

在你的程序中有两个operator<<声明采用了TWayPointList对象,一个在全局命名空间中(定义是一个自我声明)和一个在::mkilib命名空间中(来自友元声明).依赖于参数的查找是找到的::mkilib,但是从未在代码中定义过.


在更新之后,似乎这不是真正的问题,因为编译器无法找到重载(上面的答案是关于编译但未链接的代码).有些内容已经从代码更改为您对命名空间的要求.如果Waypoint和operator<<那个std::vector<Waypoint>在同一名称空间中定义了,那么ADL将找到正确的重载.请注意,DataHandler定义的命名空间没有任何效果.


实际上,现在我考虑一下,原来的答案确实适用.友元声明对查找没有任何影响,因为ADL不会查找内部DataHandler搜索该运算符,因此唯一的声明operator<<是定义中的自声明.

请注意,友元声明在名称空间级别声明实体,但声明仅在具有friend声明的类中可见.

建议:避免使用指令,它们只会带来混乱和痛苦.如果需要,重新打开命名空间或限定标识符...使用指令使查找的推理更加复杂.

  • @nightsparc:请注意,“typedef”根本不重要。编译器会将 typedef 解析为实际类型 `std::vector&lt;ns::Waypoint&gt;` ,并且模板的命名空间和模板参数(即本例中的 `::std` 和 `::ns` )将在 ADL 期间进行检查。`typedef` 可以驻留在*任何*命名空间中,但只会搜索真实类型的那些。 (2认同)