在除 ADL、“本地”或全局命名空间之外的命名空间中定义函数

Posted

技术标签:

【中文标题】在除 ADL、“本地”或全局命名空间之外的命名空间中定义函数【英文标题】:Defining a function in a namespace other than the ADL, "local" or global namespace 【发布时间】:2016-04-04 11:44:22 【问题描述】:

请看下面的代码:

#include <iostream>

/// Definition of void perform(a_lib::a_class&). Where should I put this definition?
/// See the comments below for where I've tried placing it.
// void perform(a_lib::a_class&) 
//   std::cout << "performing on a_lib::a_class" << std::endl;
// 

namespace a_lib 
  class a_class   ;

  // WORKS HERE but it pollutes a_lib (namespace of third-party library).


namespace mine 
  // DOESN'T WORK HERE: "use of undeclared identifier 'perform'".


// WORKS HERE but it pollutes the global namespace.

namespace b_lib 
  // WORKS HERE but it pollutes b_lib (namespace of third-party library).

  template <typename Type>
  void b_func(Type& obj) 
    perform(obj);
  


namespace mine 
  // DOESN'T WORK HERE: "use of undeclared identifier 'perform'".

  void run() 
    a_lib::a_class a_obj;
    b_lib::b_func(a_obj);
  


int main(int, char**) 
  mine::run();

  return 0;

a_libb_lib 是属于两个不同第三方库的命名空间。 mine 是我自己的命名空间。

我被告知污染全局命名空间是个坏主意,在this question 中,他们还说向std 添加类型是个坏主意。我认为后者通常适用于名称空间。您不应该将类型添加到不属于您的命名空间。

但是我如何在不违反这些原则的情况下解决上述问题呢?我应该把perform()的定义放在哪里,如何让b_func()调用它?

上下文:我正在尝试在我自己的命名空间中为 SFML 类型添加外部 cereal serialize()。这是一个简化的例子。

【问题讨论】:

要扩展a_lib::a_class 的接口,您应该将内容添加到该类型的命名空间。扩展您不拥有的类型的接口是否是一个好主意(例如,通过使它们可序列化)是关键问题,但如果您要这样做,那么您应该在类型的命名空间中进行。另一种选择是在您自己的命名空间中定义您自己的派生自a_class 的类型,并在您的命名空间中添加序列化支持。 “扩展你不拥有的类型的接口是否是一个好主意(例如,通过使它们可序列化)是关键问题” 这是一个非常好的观点。我将从a_class 派生。谢谢。 【参考方案1】:

你需要确定编译器在哪里,在处理“b_func”的时候可以找到“perform”。

namespace mine 
  // DOESN'T WORK HERE: "use of undeclared identifier 'perform'".

  // dom -  yes it will, but there is 'more' to the name than your example shows

  void perform(Type& obj)  /* do something with obj */



// WORKS HERE but it pollutes the global namespace.

namespace b_lib 
  // WORKS HERE but it pollutes b_lib (namespace of third-party library).

  // dom -  use here is easy with correct and 'more-complete' name:

  template <typename Type>
  void b_func(Type& obj)   mine::perform(obj); 
  // -----------------------^^^^^^^^^^^^^^^^^^^ --- more to name

由于“我的”是一个名称空间,一个更完整的名称可以“跨越”名称空间。

请注意,在我的::perform() 实现中,还必须定义“类型”才能使用 obj。

【讨论】:

如果我理解正确,您是在建议我编辑b_func() 的定义。问题是它是第三方库的一部分,因此我不应该编辑它的定义。 如果不能修改 b_func,那么 b_func() 当前必须调用已经存在的“perform()”方法/函数。顾名思义,“性能”已经在全球范围内,因此不能增加更多的“污染”。 不,它不建议这样做。大概它调用了不合格的函数,以便 ADL 找到它,以便找到在a_lib::a_class 的关联命名空间中定义的函数。 对不起,我没听说过ADL,找不到。

以上是关于在除 ADL、“本地”或全局命名空间之外的命名空间中定义函数的主要内容,如果未能解决你的问题,请参考以下文章

了解 javascript 全局命名空间和闭包

命名空间

C++ Primer 5th笔记(chap 18 大型程序工具)命名空间特性

C++命名空间与缺省参数

C++命名空间与缺省参数

C++命名空间与缺省参数