我有这个程序

#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 名称空间。对于您的电话,这些名称空间是 stdskg.

它会看两者,找不到 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拥有一个有用的指南:

  1. 将类型及其非成员函数接口保持在同一名称空间中。

跟随它,您和ADL会很高兴。我推荐这本书,即使您无法获得至少阅读我上面链接的PDF;它包含您需要的相关信息。


请注意,移动操作员后,您需要您的朋友指令(因此您可以访问私人变量):

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

和ta-da!固定的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top