Sur*_*rya 8 c++ templates outputstream operator-overloading friend
我有这个程序
#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std ;
#if 0
namespace skg
{
template <class T>
struct Triplet ;
}
template <class T>
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t) ;
#endif
namespace skg
{
template <class T>
struct Triplet
{
// friend ostream& ::operator<< <> (ostream& os, const Triplet<T>& p_t) ;
private:
T x, y, z ;
public:
Triplet (const T& p_x, const T& p_y, const T& p_z)
: x(p_x), y(p_y), z(p_z) { }
} ;
}
template <class T>
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
{
os << '(' << p_t.x << ',' << p_t.y << ',' << p_t.z << ')' ;
return os ;
}
namespace {
void printVector()
{
typedef skg::Triplet<int> IntTriplet ;
vector< IntTriplet > vti ;
vti.push_back (IntTriplet (1, 2, 3)) ;
vti.push_back (IntTriplet (5, 5, 66)) ;
copy (vti.begin(), vti.end(), ostream_iterator<IntTriplet> (cout, "\n")) ;
}
}
int main (void)
{
printVector() ;
}
Run Code Online (Sandbox Code Playgroud)
编译失败,因为编译器找不到skg :: Triplet的任何输出运算符.但是输出运算符确实存在.
如果我将Triplet从skg命名空间移动到全局命名空间,一切正常.这有什么不对?
GMa*_*ckG 13
您需要将您的实现移动operator<<到与您的类相同的命名空间中.它正在寻找:
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
Run Code Online (Sandbox Code Playgroud)
但由于参数依赖查找(ADL)的短缺,因此无法找到它.ADL意味着当你调用一个自由函数时,它会在它的参数的名称空间中查找该函数.这与我们可以做的原因相同:
std::cout << "Hello" << std::endl;
Run Code Online (Sandbox Code Playgroud)
即使operator<<(std::ostream&, const char*)在std命名空间中.对于您的调用,这些名称空间是std和skg.
它会在两者中找到,而不是找到一个skg(因为你的是在全球范围内),然后查看std.它会看到可能性(所有正常情况operator<<),但这些都不匹配.因为运行的代码(代码ostream_iterator)在命名空间中std,所以对全局命名空间的访问完全消失了.
通过将运算符放在同一名称空间中,ADL可以正常工作.Herb Sutter在一篇文章中讨论了这个问题:"一个适度的提案:修复ADL"..(PDF).事实上,这是文章的一个片段(展示了一个缺点):
// Example 2.4
//
// In some library header:
//
namespace N { class C {}; }
int operator+( int i, N::C ) { return i+1; }
// A mainline to exercise it:
//
#include <numeric>
int main() {
N::C a[10];
std::accumulate( a, a+10, 0 ); // legal? not specified by the standard
}
Run Code Online (Sandbox Code Playgroud)
你有同样的情况.
Sutter和&Alexandrescu 撰写的"C++编码标准"一书有一个有用的指导原则:
- 将类型及其非成员函数接口保留在同一名称空间中.
跟着它,你和ADL会很开心.我推荐这本书,即使你不能得到一本至少阅读我上面链接的PDF; 它包含您应该需要的相关信息.
请注意,移动运算符后,您将需要您的friend指令(因此您可以访问私有变量):
template <typename U>
friend ostream& operator<< (ostream& os, const Triplet<U>& p_t);
Run Code Online (Sandbox Code Playgroud)
和ta-da!固定.
| 归档时间: |
|
| 查看次数: |
4428 次 |
| 最近记录: |