命名空间中类模板的超载输出操作员
-
23-09-2019 - |
题
我有这个程序
#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() ;
}
编译失败,因为编译器找不到SKG ::三重态的任何输出操作员。但是输出操作员确实存在。
如果我将三胞胎从SKG名称空间移动到全局名称空间,则一切正常。这里怎么了?
解决方案
您需要移动实施 operator<<
与您的班级相同的名称空间。它正在寻找:
ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)
但由于参数依赖性查找(ADL)的短暂差异,因此找不到它。 ADL意味着当您调用免费函数时,它将在其参数的名称空间中查找该函数。这是我们可以做的同样原因:
std::cout << "Hello" << std::endl;
虽然 operator<<(std::ostream&, const char*)
在里面 std
名称空间。对于您的电话,这些名称空间是 std
和 skg
.
它会看两者,找不到 skg
(因为您的在全球范围中),然后看一下 std
. 。它将看到可能性(所有正常 operator<<
s),但这些都没有匹配。 因为运行的代码(代码中的代码 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
}
你有同样的情况。
这本书 “ C ++编码标准” Sutter and&&Alexandrescu拥有一个有用的指南:
- 将类型及其非成员函数接口保持在同一名称空间中。
跟随它,您和ADL会很高兴。我推荐这本书,即使您无法获得至少阅读我上面链接的PDF;它包含您需要的相关信息。
请注意,移动操作员后,您需要您的朋友指令(因此您可以访问私人变量):
template <typename U>
friend ostream& operator<< (ostream& os, const Triplet<U>& p_t);
和ta-da!固定的。
不隶属于 StackOverflow