6

Consider this library header:

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

Does the detail namespace successfully isolate the clients of the library (and the rest of library's implementation) from the using-directive in this example? I'm not interested in the discussion at Why is "using namespace std" considered bad practice?, even though some of the arguments apply even to "well contained" using-directives.

Note that there are two existing questions concerning the same situation but with using-declarations:

This could be combined with either of them, but the editing would be severe.

L. F.
  • 19,445
  • 8
  • 48
  • 82
Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • You should move `using namespace std;` into `sort_impl`. Then you'll be fine. – Henri Menke Sep 12 '17 at 05:09
  • If the using-directive is in `sort_impl`, you have to qualify the `istream` and `ostream` in its signature. (Not a catastrophe, but avoiding such verbosity is the reason for the using-directive!) You also have to have one for every function. – Davis Herring Sep 12 '17 at 13:38

2 Answers2

8

You pollute your own detail namesapce, but not the Lib or global namespaces. So assuming a responsible adult is using your library, they won't have unintentional name collisions:

#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
}
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Would an additional anonymous namespace be recommended here? – Passer By Sep 12 '17 at 05:54
  • 1
    @PasserBy - No. If `Lib` is declared in a header, then I think that may cause ODR violations for any type declared within. Anonymous namespaces are "different" in every translation unit. – StoryTeller - Unslander Monica Sep 12 '17 at 05:56
  • 2
    +1 This should be the accepted answer. Isolation is not about protection against intentional abuse but simply about enabling users that behave to stay save from unwanted side effects. – DrSvanHay Sep 12 '17 at 10:10
3

No, the detail namespace will not isolate clients from the nested using directive. [namespace.udir] is quite explicit about that

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup, the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [ Note: In this context, “contains” means “contains directly or indirectly”. — end note ]

A little example

#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 gives a nice explanation of how name lookup works in his video Core C++, 1 of n.

Henri Menke
  • 10,705
  • 1
  • 24
  • 42
  • 4
    The whole point of a `detail` namespace is to put implementation details there. Developers are expected to be adults and not just pull the details in. Works in libraries like boost. I think you misunderstood the OP's intent. They want to prevent accidental name collision, not clients shooting themselves in the foot. – StoryTeller - Unslander Monica Sep 12 '17 at 05:45
  • 1
    I think OP is asking about non abusing cases – Passer By Sep 12 '17 at 05:48
  • @StoryTeller »Make interfaces easy to use correctly and hard to use incorrectly.« (Scott Meyers) If you can do `using namespace detail;` someone will do it. Hence, protect everyone, by not having `using namespace` declarations at namespace or global scope. – Henri Menke Sep 12 '17 at 05:56
  • 3
    @HenriMenke - I agree with Scott. Hence the detail namespace is not part of the interface. You are somewhat misrepresenting what he said. The responsible adult approach works in plenty C++ header only libraries. I already named boost, but you should lookup what the standard library headers do as well, if you aren't convinced. – StoryTeller - Unslander Monica Sep 12 '17 at 05:58
  • 2
    Also, it's not that your answer is incorrect, it is (+1). It's just overly cautious in my opinion. – StoryTeller - Unslander Monica Sep 12 '17 at 06:00