gpt4 book ai didi

c++ - 为命名空间中的类模板重载输出运算符

转载 作者:可可西里 更新时间:2023-11-01 17:36:03 27 4
gpt4 key购买 nike

我有这个程序

#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::Triplet 的任何输出运算符。但是输出运算符确实存在。

如果我将 Triplet 从 skg 命名空间移动到全局命名空间,一切正常。这里有什么问题?

最佳答案

您需要移动 operator<< 的实现进入与您的类(class)相同的 namespace 。它正在寻找:

ostream& operator<< (ostream& os, const skg::Triplet<T>& p_t)

但由于参数相关查找 (ADL) 的缺陷,无法找到它。 ADL 意味着当您调用自由函数时,它会在其参数的 namespace 中查找该函数。这与我们可以这样做的原因相同:

std::cout << "Hello" << std::endl;

尽管operator<<(std::ostream&, const char*)std命名空间。对于您的调用,这些 namespace 是 stdskg .

它将在两者中查找,而不是在 skg 中找到一个(因为你的在全局范围内),然后查看 std .它会看到可能性(所有正常的 operator<< 的),但这些都不匹配。 因为运行的代码(ostream_iterator 中的代码)在命名空间 std 中,对全局命名空间的访问完全消失了。

通过将您的运算符放在同一个命名空间中,ADL 可以正常工作。 Herb Sutter 在一篇文章中对此进行了讨论: "A Modest Proposal: Fixing 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
}

和你一样的情况。

Sutter 和 & Alexandrescu 合着的“C++ 编码标准” 一书有一个有用的指南:

  1. Keep a type and its nonmember function interface in the same namespace.

跟着它走,你和 ADL 都会很开心。我推荐这本书,即使你买不到,至少也可以阅读我上面链接的 PDF;它包含您应该需要的相关信息。


请注意,在移动运算符后,您需要 friend 指令(以便您可以访问私有(private)变量):

template <typename U>
friend ostream& operator<< (ostream& os, const Triplet<U>& p_t);

还有哒哒!固定。

关于c++ - 为命名空间中的类模板重载输出运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2159713/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com