我有一些问题让我受到欢迎。我已经键入了一个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有关,但我没有明白这一点。
那么,任何想法和想法都能让代码发挥作用吗?
[编辑] 我在源代码和错误输出中添加了一些文件以便澄清。
答案 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
中找到的,但是从未在代码中定义过。
更新后似乎这不是真正的问题,因为编译器无法找到重载(上面的答案是关于编译但未链接的代码)。有些内容已经从代码更改为您对命名空间的要求。如果在同一名称空间中定义Waypoint
和operator<<
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;
}
}