具有来自另一个命名空间的 typedef 的 ADL

发布于 2024-10-02 15:27:10 字数 669 浏览 0 评论 0原文

我有这样的事情:

#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 NMyPair 没有关联代码>(不幸的是)。据我所知,可能不会添加到命名空间 std,因此如果我选择在 std 中定义运算符 <<,那将是一种非法。那么...遇到这种情况该怎么办?我不想显式限定operator <<,也不希望编写using namespace N。那么问题来了:

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

I have something like this:

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

This naturally doesn't work, because ADL won't find operator<< because namespace N is not associated with MyPair (unfortunately). Afaik one may not add to namespace std, so if I chose to define operator << in std that would be kinda illegal. So... what to do in such situations? I don't want to explicitly qualify operator <<, nor do I wish to write using namespace N. So, questions are:

  1. How to refactor the code?
  2. Why wouldn't ADL associate namespaces of typedefs? Serious reasons? It would be nice, e.g. in this case. Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

沉鱼一梦 2024-10-09 15:27:10
  1. 您可以在命名空间 N 中创建自己的类型,可能继承自 std::pair。您可以添加“using namespace 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; }
  1. You could create your own type in namespace N, possibly inheriting from std::pair. You could add "using namespace N;" inside main. The former is more likely to be useful.

  2. Because the type is defined in another namespace and cannot be defined in two.

Example:

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

If being used as a std::pair isn't important, you can drop the inheritance and rename the members. In either case you can, of course, add additional methods, but if you keep the inheritance you can use "renaming methods":

int      & foo()       { return first; }
int const& foo() const { return first; }
double      & bar()       { return second; }
double const& bar() const { return second; }
醉生梦死 2024-10-09 15:27:10

我想不出 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(), [...]);
} 
  • 如果 std::vector::iterator 是位于 std 命名空间中的某个内容的 typedef:std::for_each 将被调用
  • 如果 std::vector::iteratormy::A * 的 typedef:编译器应该抱怨 my:: for_each 不接受 3 个参数

I can't think of a reason why typedef names should not participate in ADL. Furthermore, it makes the following code implementation defined :

#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(), [...]);
} 
  • If std::vector<T>::iterator is a typedef for something which sits in the std namespace : std::for_each will be called
  • If std::vector<T>::iterator is a typedef for my::A * : the compiler should complain that my::for_each doesn't take 3 arguments
苏璃陌 2024-10-09 15:27:10

您的选择是:

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

这一切都源于 typedef 的主要优点和缺点: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);

Your options are to:

  • Define a new type which uses std::pair in its implementation, instead of using typedef
  • Use a different name for your output function
  • Explicitly qualify the function you want when you call it
  • (Maybe) Specialize the function in namespace std (I'm not sure if pair<int,double> counts as a UDT)

This all stems from the main strength and weakness of typedefs: typedef names are just synonyms. It doesn't matter what namespace you put it in, the typedef name refers to the associated type, in whatever namespace that type is defined in. This is distinct from a typedef being a new type that is convertible to/from the associated type. Imagine this scenario:

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

This is invalid, because int and id_t aren't distinct types. This extends to 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

And here's a question for you: Do you believe that the following should fail to compile? If not, how should the name lookup be resolved:

B::id_t id;
g(id);
遮云壑 2024-10-09 15:27:10

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

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

I solve this problem by pulling the relevant symbol(s) into the namespace I want to use them from:

#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;
}
回忆追雨的时光 2024-10-09 15:27:10

您可以使用强类型定义:(

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

额外的类型定义仍然是必要的,以避免宏中出现额外的逗号。)

You can use a strong typedef:

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

(The extra typedef is still necessary to avoid the extra comma in the macro.)

夜唯美灬不弃 2024-10-09 15:27:10

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

struct myPair
{
  int first;
  double second;
};

If you have a specific data type which you want to output, you can always define your own class rather than use std::pair.

struct myPair
{
  int first;
  double second;
};
苦行僧 2024-10-09 15:27:10

允许namespace::std添加模板函数的专门化,但是由于MyPair中使用的类型都不是用户定义的,我不确定这样的专业化是否合法。

namespace std {
     template<>
     ostream& operator<<(ostream& os, const MyPair& p) { }
}

It is allowed to add specialization of template functions to namespace::std however since none of the types used in MyPair is user defined I'm not sure such a specialization is legal.

namespace std {
     template<>
     ostream& operator<<(ostream& os, const MyPair& p) { }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文