59

Is it safe (and correct) in a C++ header file to use the using declaration within a namespace as follows:

#include <boost/numeric/ublas/vector.hpp>
namespace MyNamespace {
    using boost::numeric::ublas::vector;
    vector MyFunc(vector in);
}

I.e. is the "using boost::numeric::ublas::vector" properly contained within the MyNamespace block, or will this pollute the namespace of any file that includes this header?

Enlico
  • 23,259
  • 6
  • 48
  • 102
Brett Ryland
  • 1,045
  • 1
  • 9
  • 17
  • 3
    What exactly do you mean by "the namespace of any file"? It will "pollute" the `MyNamespace` namespace in any translation unit from the point of the declaration of the using declaration onwards. – CB Bailey May 30 '11 at 11:36
  • for a single symbol... why don't you use a `typedef` ? – Matthieu M. May 30 '11 at 12:11
  • 1
    @Matthieu: Because `boost::numeric::ublas::vector` is a template. I was previously using the standard "template typedef" workaround (http://stackoverflow.com/questions/26151/template-typedefs-whats-your-work-around), but wanted to simplify things a bit. – Brett Ryland May 30 '11 at 12:19
  • 2
    argh! In C++0x you have ways to alias templates... though you need redeclare all the arguments you wish to use, but otherwise you are kind of stuck, I guess. – Matthieu M. May 30 '11 at 12:24

5 Answers5

45

No, it is not safe - it won't pollute another namespace, but it is dangerous for other reasons:

A using directive will import anything that is currently visible by the name you specify into the namespace where you use it. While your using will only be visible to users of MyNamespace, other things from "outside" will be visible to your using declaration.

So how is this dangerous when used in a header? Because it will import things that are visible at the point of the declaration, the exact behavior will depend on the order of headers you include before the declaration (There might be different things visible from boost::numeric::ublas::vector). Since you cannot really control which headers are included before your header (nor should you be! headers should be self-sufficient!), this can lead to very strange problems where your function will find one thing in one compilation unit, and another in the next.

As a rule of thumb, using declarations should only be used after all includes in a .cpp file. There's also an item on this exact issue in the book "C++ Coding Standards" by Sutter and Alexandrescu (Item 59). Here's a quote:

But here's the common trap: Many people think that using declarations issued at namespace level (...) are safe. They are not. They are at least as dangerous, and in a subtler and more insidious way.

Even when it's unlikely that the name you are using doesn't exist anywhere else (as is probably the case here), things can get ugly: In a header, all declarations should be fully qualified. This is pain, but otherwise, strange things can happen.

Also see Migrating to Namespaces, Using-declarations and namespace aliases and Namespace Naming for examples and the problem described in-depth.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
ltjax
  • 15,837
  • 3
  • 39
  • 62
  • 4
    Note that I am using `using boost::numeric::ublas::vector`, not `using namespace boost::numeric::ublas` as I don't want to import the entire `boost::numeric::ublas` namespace. Also, since this is declared inside the `namespace MyNamespace { }` block, shouldn't vector only be ambiguous if someone wrote something like `using namespace std; using namespace MyNamespace;`? – Brett Ryland May 30 '11 at 12:00
  • No, it'll be ambiguous since std::vector is aliased as vector and that is used in your header (because the header is included after the `using namespace std`). It won't even compile! – ltjax May 30 '11 at 12:04
  • Using a single name is potentially a little less scary than importing a whole namespace, but nevertheless, the same issues apply. – ltjax May 30 '11 at 12:07
  • 4
    @ltjax: What exactly do you mean will be ambiguous? Inside `MyNamespace` the `vector` introduced by the using _declaration_ will hide any vector visible in the global namespace introduced by a using _directive_. Surely this is the intention? – CB Bailey May 30 '11 at 12:10
  • @Charles: oops, you are correct, my bad. The point is still valid tho. Sutter has a good example on this, but it uses functions. Just need to find one with types. – ltjax May 30 '11 at 12:18
  • 3
    "The point is still valid tho." Perhaps, although I must say that I don't yet see what the issue is for types. – CB Bailey May 30 '11 at 12:19
  • For example, someone could define `MyFunction::boost::numeric::ublas::vector`, and it'll change the meaning of the code in the header. But this is unlikely and can easily be fixed by `using ::boost::numeric::ublas::vector`. Sutter's example uses function overloads, so I guess template specialization could mess things up for types. – ltjax May 30 '11 at 12:23
  • @Charles: The GotW link I posted has an example, although it doesn't seem as severe as using declarations on functions because it does not silently change the meaning. Usually, the compiler will complain for ambiguities . – ltjax May 30 '11 at 12:51
  • 3
    @ltjax: So in conclusion, if I used `using ::boost::numeric::ublas::vector` inside the namespace block in my header file, would this avoid possible ambiguities in my header file? If someone later calls `using namespace std; using namespace MyNamespace` in a .cpp file this will cause ambiguity, but so would `using namespace std; using namespace boost::numeric::ublas;`... so there isn't much of a problem, yes? – Brett Ryland May 30 '11 at 13:19
  • 1
    @Brett: it would avoid some of the more dangerous ambiguities, but you're not totally safe. For example, someone could implement another `vector` in `MyNamespace` (and that doesn't have to be you), in which case you get a compile error, whenever those two files are included in the same cpp. This can be avoided by using the fully qualified name everywhere in the interface. The whole thing is a lot more severe with functions really. – ltjax May 30 '11 at 19:23
  • 7
    I've also been looking for ways to make a more readable syntax without too much `std::` prefix. I'd really like to use `using ::std::vector` inside my own namespace before I define my classes so that the code reads easier. I understand that `using namespace` is risky, and I can understand the issue if `using` declaration for functions. But from what I understand the only issue with types is a possibility of conflict if "someone else" should define an identically named type in my namespace. Is this really such a big problem that no one use this pattern? – thomthom Dec 15 '13 at 22:19
  • So you have 'created' the type `MyNamespace::vector`. That sounds safe enough in itself. – Will Nov 24 '17 at 11:57
15

A using declaration is, as the name says, a declaration. All declarations are scoped to the enclosing block (7.2), in this case the namespace MyNamespace. It will not be visible outside that namespace.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 1
    Thanks, I think this is what I'm trying to get. Basically, I want all the vectors in this namespace to be `boost::numeric::ublas::vector`s so that any .cpp file that includes this header and uses the `using namespace MyNamespace;` declaration uses this vector instead of the `std::vector`. But not otherwise. – Brett Ryland May 30 '11 at 11:51
  • 2
    @Brett: And if they have a `using namespace std;` you have a name-clash. I always prefer fully qualified names. You can always create a short alias for a namespace. – Björn Pollex May 30 '11 at 11:54
  • 3
    "It will not be visible outside that namespace." - while this is correct, the reverse it not: outside stuff will be visible to the using directive, potentially changing the meaning of your and other people's code. – ltjax May 30 '11 at 12:00
5

It is safe, but it will pollute the MyNamespace namespace. So, any file that include that header will have functions/classes in the MyNamespace.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
4

To summarize, no, using-declarations in a header are not ok, even within a namespace, for 2 reasons. Further, using-declarations within a namespace in a non-header are error-prone or pointless (see end). Using-declarations in a header are not ok because:

  1. They introduce a name into the namespace, which affects all files that include the header.
  2. They introduce only declarations for the name that have already been seen, which means that behavior depends on order of includes!

In your example, this means that:

  1. Within MyNamespace, vector now may resolve to boost::numeric::ublas::vector, for any files that include this header: it "pollutes" the MyNamespace namespace.
  2. Which boost::numeric::ublas::vector declarations are imported depends on what declarations appear before this using-declaration, which depends on the order of includes in the file that includes this header, and all of its includes (properly, the order of declarations in the translation unit, after preprocessing).

Per your comment of May 30 '11 at 11:51 you actually want behavior 1, but this doesn't work, due to problem 2. You can get the desired behavior by having a separate header that is included after all others (and fully qualifying the name in other headers). However, this is fragile and thus discouraged, preferably being reserved only when transitioning to namespaces:

//--- file myheader.hpp ---
#include <boost/numeric/ublas/vector.hpp>
namespace MyNamespace {
    ::boost::numeric::ublas::vector MyFunc(::boost::numeric::ublas::vector in);
}

//--- file myproject_last.hpp ---
namespace MyNamespace {
    using ::boost::numeric::ublas::vector;
}

//--- file myproject.cpp ---
#include "myheader.hpp"
// ...other includes
#include "myproject_last.hpp"

See GotW #53: Migrating to Namespaces for details, this workaround, and advice: "Namespace using declarations should never appear in header files."

It is possible to avoid problem 1 by adding an unnamed namespace around the using-declaration (to prevent those names from being visible) and then another one outside the unnamed namespace (to make the desired name itself visible), but that still suffers from problem 2 and uglifies the header:

//--- file myheader.hpp ---
#include <boost/numeric/ublas/vector.hpp>
namespace MyNamespace {
    namespace {
        using ::boost::numeric::ublas::vector;
        vector MyFunc(vector in);
    }
    using MyFunc; // MyNamespace::(unique)::MyFunc > MyNamespace::MyFunc
}

Due to these problems, you should only use using-declarations in non-header (.cc/.cpp) files: this doesn't affect other files, so problem 1 is avoided; and all headers have been included, so problem 2 is avoided. In this case it's a matter of taste whether you put them in a namespace or not, since they don't affect other files; it's safest to always use fully qualified names on in the using-declaration itself (absolute, starting with ::).

Simplest is to put all using-declarations at the top of the file, after the includes, but outside of any namespaces: this is safe, unambiguous, easy to read, and allows the names to be used throughout the file. Some common deviations:

  1. Using-declaration within a function (or struct or class or nested block): fine. This minimizes scope and is just a matter of taste: using-declaration is close to use (legibility win), but they are now scattered throughout the file (legibility loss).
  2. Using-declaration with a relative name within a (named) namespace: error-prone. This is more concise and adds some clarity (related names used in the namespace to which they relate), but is potentially ambiguous (just like includes with relative paths), and is safer to avoid:

    using ::foo::bar;
    namespace foo { ... }
    
    namespace foo {
        // Implicitly ::foo:bar, could be ::bar, or ::other::foo::bar.
        using bar;
    }
    
  3. Using-declaration with an absolute name within a named namespace: pointless. This introduces the name only into the namespace, but you shouldn't care, since you shouldn't be including the .cc/.cpp file:

    namespace foo {
        using ::bar;
    }
    
  4. Using-declaration within an unnamed namespace: pointless, slightly dangerous. For example, if you have a function in an unnamed namespace, say an implementation detail, then you can have a using-declaration for its return type or param types. This introduces the name into just that namespace (so can't be referenced from other files), but again, you shouldn't care, since you shouldn't be including the .cc/.cpp file (unnamed namespaces are especially for avoid name clashes at link time, which isn't applicable here: it's just a compile-time alias). Worse, it introduces ambiguity if that name already does exist!

Community
  • 1
  • 1
Nils von Barth
  • 3,239
  • 2
  • 26
  • 27
1

It will not pollute any other namespaces, but it certainly will pollute the MyNamespace namespace.

Puppy
  • 144,682
  • 38
  • 256
  • 465