简体   繁体   English

为命名空间中的类模板重载Output运算符

[英]Overloading Output operator for a class template in a namespace

I've this program 我有这个程序

#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() ;
}

Compilation fails because compiler could not find any output operator for skg::Triplet. 编译失败,因为编译器找不到skg :: Triplet的任何输出运算符。 But output operator does exist. 但是输出运算符确实存在。

If I move Triplet from skg namespace to global namespace everything works fine. 如果我将Triplet从skg命名空间移动到全局命名空间,一切正常。 what is wrong here ? 这有什么不对?

You need to move your implementation of operator<< into the same namespace as your class. 您需要将operator<<的实现移动到与您的类相同的命名空间中。 It's looking for: 它正在寻找:

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

But won't find it because of a short-coming in argument-dependent look-up (ADL). 但由于参数依赖查找(ADL)的短缺,因此无法找到它。 ADL means that when you call a free function, it'll look for that function in the namespaces of it's arguments. ADL意味着当你调用一个自由函数时,它会在它的参数的名称空间中查找该函数。 This is the same reason we can do: 这与我们可以做的原因相同:

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

Even though operator<<(std::ostream&, const char*) is in the std namespace. 即使operator<<(std::ostream&, const char*)std命名空间中。 For your call, those namespaces are std and skg . 对于您的调用,这些名称空间是stdskg

It's going to look in both, not find one in skg (since yours is in the global scope), then look in std . 它会在两者中查找,而不是在skg找到一个(因为你的是在全局范围内),然后查看std It will see possibilities (all the normal operator<< 's), but none of those match. 它将看到可能性(所有正常的operator<< s),但这些都不匹配。 Because the code running (the code in ostream_iterator ) is in the namespace std , access to the global namespace is completely gone. 因为运行的代码( ostream_iterator的代码)位于命名空间std ,所以对全局命名空间的访问完全消失了。

By placing your operator in the same namespace, ADL works. 通过将运算符放在同一名称空间中,ADL可以正常工作。 This is discussed in an article by Herb Sutter: "A Modest Proposal: Fixing ADL." Herb Sutter在一篇文章中讨论了这个问题: “一个适度的提案:修复ADL”。 . (PDF). (PDF)。 In fact, here's a snippet from the article (demonstrating a shortcoming): 事实上,这是文章的一个片段(展示了一个缺点):

// 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
}

Same situation you have. 你有同样的情况。

The book "C++ Coding Standards" by Sutter and & Alexandrescu has a useful guideline: Sutter和&Alexandrescu撰写的“C ++编码标准”一书有一个有用的指导原则:

  1. Keep a type and its nonmember function interface in the same namespace. 将类型及其非成员函数接口保留在同一名称空间中。

Follow it and you and ADL will be happy. 跟着它,你和ADL会很开心。 I recommend this book, and even if you can't get one at least read the PDF I linked above; 我推荐这本书,即使你不能得到一本至少阅读我上面链接的PDF; it contains the relevant information you should need. 它包含您应该需要的相关信息。


Note that after you move the operator, you'll need your friend directive (so you can access private variables): 请注意,移动运算符后,您将需要您的friend指令(因此您可以访问私有变量):

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

And ta-da! 和ta-da! Fixed. 固定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM