18

我有这样的事情:

#include <iostream>
namespace N
{
   typedef std::pair<int, double> MyPair;
   std::ostream& operator << (std::ostream& o, MyPair const & mypair)
   {
      ///
   }
}

int main()
{
    N::MyPair pr;
    std::cout << pr;
}

这自然是行不通的,因为 ADL 找不到,operator<<因为namespace N没有关联MyPair(很遗憾)。Afaik 可能不会添加到命名空间 std,所以如果我选择operator <<在 std 中定义那将是非法的。那么......在这种情况下该怎么办?我不想明确限定operator <<,也不想写using namespace N。所以,问题是:

  1. 如何重构代码?
  2. 为什么 ADL 不关联 typedef 的命名空间?严重的原因?这会很好,例如在这种情况下。谢谢
4

7 回答 7

4
  1. 您可以在命名空间 N 中创建自己的类型,可能继承自 std::pair。您可以添加“使用命名空间 N;” 里面主要。前者更有可能有用。

  2. 因为类型是在另一个命名空间中定义的,不能在两个中定义。

例子:

namespace N { 
struct MyPair : std::pair<int, double> {
  MyPair(int first, double second) : std::pair<int, double>(first, second) {}
  // add defaults if desired: first=0, second=0.0
  // with defaults, you may want to make the ctor explicit or leave implicit

  // also, if desired and you don't use two defaults above:
  MyPair() : std::pair<int, double>(0, 0.0) {}

  // in 0x, you can "import" the base's ctors with a using declaration
};
}

如果用作 std::pair 并不重要,则可以删除继承并重命名成员。当然,无论哪种情况,您都可以添加其他方法,但如果您保留继承,则可以使用“重命名方法”:

int      & foo()       { return first; }
int const& foo() const { return first; }
double      & bar()       { return second; }
double const& bar() const { return second; }
于 2010-11-11T14:41:28.660 回答
4

我想不出typedef名称不应该参与 ADL 的原因。此外,它定义了以下代码实现:

#include <algorithm>
#include <vector>

namespace my {
class A {};
void for_each();
} // my

int main()
{
    std::vector<my::A> v;
    for_each(v.begin(), v.end(), [...]);
} 
  • Ifstd::vector<T>::iterator是位于 std 命名空间中的东西的 typedef :std::for_each将被调用
  • If std::vector<T>::iteratoris a typedef for my::A *: 编译器应该抱怨my::for_each不接受 3 个参数
于 2010-11-11T15:39:07.147 回答
2

您的选择是:

  • 定义一个在其实现中使用 std::pair 的新类型,而不是使用 typedef
  • 为输出函数使用不同的名称
  • 调用时明确限定您想要的函数
  • (也许)专门化命名空间 std 中的函数(我不确定是否pair<int,double>算作 UDT)

这一切都源于 typedef 的主要优点和缺点:typedef 名称只是同义词。不管你把它放在哪个命名空间中,typedef 名称都是指关联的类型,在该类型定义的任何命名空间中。这与 typedef 是不同的,它是可转换为关联类型/从关联类型转换的新类型。想象一下这个场景:

class C{};
typedef C id_t;
void f(C);
int f(id_t); // error: structurally equivalent to `int f(C);`

这是无效的,因为 int 和 id_t 不是不同的类型。这延伸到 ADL:

namespace A{
  class C{};
  void f(C);
  void g(C);
}

namespace B{
  typedef C id_t;
  int f(id_t); // structurally equivalent to `void f(C);`
}

B::id_t id; // completely equivalent to `A::C id;`
int n = f(id); // error: A::f doesn't return int

这里有一个问题要问您:您是否认为以下内容应该无法编译?如果不是,应该如何解决名称查找:

B::id_t id;
g(id);
于 2010-11-11T16:31:58.107 回答
2

我通过将相关符号拉入我想要使用它们的命名空间来解决这个问题:

#include <iostream>

namespace N
{
   typedef std::pair<int, double> MyPair;
   std::ostream& operator << (std::ostream& o, MyPair const & mypair)
   {
      ///
   }
}

using N::operator <<; // now it should compile

int main()
{
    N::MyPair pr;
    std::cout << pr;
}
于 2014-07-12T13:53:08.147 回答
2

您可以使用强类型定义:

#include<boost/strong_typedef.hpp>    
#include<iostream>

namespace N
{
// typedef std::pair<int, double> MyPair;
   typedef std::pair<int, double> pair_int_double; 
   BOOST_STRONG_TYPEDEF(pair_int_double, MyPair);

   std::ostream& operator << (std::ostream& o, MyPair const & mypair)
   {
      return o;
   }
}

int main(){
    N::MyPair pr;
    std::cout << pr;
}

(仍然需要额外的 typedef 以避免宏中的额外逗号。)

于 2015-01-14T10:13:21.880 回答
1

如果您有要输出的特定数据类型,您始终可以定义自己的类而不是使用std::pair.

struct myPair
{
  int first;
  double second;
};
于 2010-11-11T14:42:06.870 回答
1

允许向其中添加模板函数namespace::std特化,但是因为其中使用的类型都不MyPair是用户定义的,所以我不确定这样的特化是否合法。

namespace std {
     template<>
     ostream& operator<<(ostream& os, const MyPair& p) { }
}
于 2010-11-11T15:45:34.350 回答