C ++重载<<具有typedef'd std :: vector的运算符

时间:2012-10-09 20:16:13

标签: c++ operator-overloading

我有一些问题让我受到欢迎。我已经键入了一个std::vector,其中包含一些自己的类:

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

这是结构DataHandler中的嵌套类型,它在某些名称空间data中有效。

所以,现在我想打印出矢量的单个内容。为此,我的想法是重载&lt;&lt;运算符和循环遍历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

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

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有关,但我没有明白这一点。

那么,任何想法和想法都能让代码发挥作用吗?

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

2 个答案:

答案 0 :(得分:6)

friend声明在具有此类friend声明的类的名称空间中声明了名称空间级别的函数。从运算符的定义来看,似乎是在全局命名空间中定义它(顺便提一下你在朋友声明中的评论所说的,太糟糕的编译器不会读取注释)。您需要在正确的命名空间中定义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<<声明了TWayPointList对象,一个在全局命名空间中(定义是一个自我声明),另一个在::mkilib命名空间中(来自朋友宣言)。依赖于参数的查找是在::mkilib中找到的,但是从未在代码中定义过。


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


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

请注意,友元声明在命名空间级别声明一个实体,但该声明仅在具有友元声明的类 中可见。

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

答案 1 :(得分: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;
    }
}