【问题标题】:Is a using-directive in a detail namespace problematic?详细命名空间中的 using 指令是否有问题?
【发布时间】:2018-02-20 10:22:47
【问题描述】:

考虑这个库头:

#include<vector>
#include<algorithm>
#include<iostream>

namespace Lib {
  namespace detail {
    using namespace std;

    template<class T>
    void sort_impl(istream &in,ostream &out) {
      vector<T> v;
      {
        int n;
        in >> n;
        v.resize(n);
      }
      for(auto &i : v) cin >> i;

      sort(v.begin(),v.end());
      for(auto i : v) out << i << endl;
    }
  }

  inline void sort_std() {
    detail::sort_impl<int>(std::cin,std::cout);
  }
}

在本例中,detail 命名空间是否成功地将库的客户端(以及库的其余实现)与 using-directive 隔离开来?我对Why is "using namespace std" considered bad practice? 的讨论不感兴趣,尽管其中一些论点甚至适用于“包含良好的”using-directives

请注意,存在两个关于相同情况但使用 using-declarations 的问题:

这可以与其中任何一个结合,但编辑会很严重。

【问题讨论】:

  • 您应该将using namespace std; 移动到sort_impl。那你就没事了。
  • 如果 using 指令在 sort_impl 中,您必须在其签名中限定 istreamostream。 (不是灾难,但避免这种冗长是使用指令的原因!)您还必须为每个函数都有一个。

标签: c++ namespaces using-directives


【解决方案1】:

detail 命名空间不会将客户端与嵌套的 using 指令隔离开来。 [namespace.udir] 对此非常明确

using-directive 指定指定命名空间中的名称可以在using-directive 出现在using-directive 之后的范围内使用。在unqualified name lookup 期间,名称看起来好像它们是在最近的封闭命名空间中声明的,其中包含using-directive 和指定的命名空间。 [ 注意:在此上下文中,“包含”是指“直接或间接包含”。 — 尾注 ]

一个小例子

#include <iostream>

namespace foo {
    namespace detail {
        using namespace std;
    }
}

int main()
{
    foo::detail::cout << "Hello World!\n";

    // nothing is stopping me from doing that
    using namespace foo::detail;
    cout << "Hello World!\n";
}

STL 在他的视频Core C++, 1 of n 中很好地解释了名称查找的工作原理。

【讨论】:

  • detail 命名空间的全部意义在于将实现细节放在那里。开发人员应该是成年人,而不仅仅是拉细节。在像 boost 这样的库中工作。我认为您误解了 OP 的意图。他们希望防止意外的名称冲突,而不是客户在脚下开枪。
  • 我认为 OP 是在询问非滥用案件
  • @StoryTeller »使界面易于正确使用,但难以正确使用。« (Scott Meyers) 如果你能做到using namespace detail;,就会有人做到。因此,通过在命名空间或全局范围内不使用 using namespace 声明来保护每个人。
  • @HenriMenke - 我同意斯科特的观点。因此,详细名称空间不是接口的一部分。你对他说的话有些曲解。负责任的成人方法适用于大量仅 C++ 标头的库。我已经命名了 boost,但如果你不相信,你也应该查找标准库头文件的作用。
  • 另外,不是你的答案不正确,而是 (+1)。在我看来,这只是过于谨慎了。
【解决方案2】:

您污染了自己的 detail 命名空间,但不会污染 Lib 或全局命名空间。所以假设一个负责任的成年人正在使用你的图书馆,他们不会有无意的名字冲突:

#include <vector>

namespace Lib {
  namespace detail {
    using namespace std;
  }
}

using namespace Lib;

int main() {
    vector<int> v; // This is an error, vector not declared in this scope
}

【讨论】:

  • 这里推荐一个额外的匿名命名空间吗?
  • @PasserBy - 否。如果 Lib 在标头中声明,那么我认为这可能会导致其中声明的任何类型的 ODR 违规。每个翻译单元中的匿名命名空间都是“不同的”。
  • +1 这应该是公认的答案。隔离不是为了防止故意滥用,而只是为了让行为正常的用户避免不必要的副作用。
猜你喜欢
  • 2011-02-26
  • 2010-12-27
  • 1970-01-01
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多