Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Name Resolution

I'm wondering a bit about the namespace and using in C++ basically I would like to know the differences and figure out how to use it in the best way.

As I see it there are (at least) three ways to resolve a class name and I am not sure how to choose among them:

  1. using namespace <namespace>
  2. using <namespace>::<what_to_use>
  3. <namespace>::<what_to_use> <use_it>

I would like to know the advantages especially if there are performance involved in one or the other way, if it's just syntactical and a matter of preference or if there are other things I haven't considered regarding this.

like image 839
qrikko Avatar asked Jan 03 '13 10:01

qrikko


2 Answers

First is an using namespace directive, it brings all the symbol names from the specified namespace in your current namespace, irrespective of whether you need/use them. Certainly undesirable.

Second is using namespace declaration. It only brings the specified symbol name in your current namespace. Advantage is you don't have to type the fully qualified name everytime.

Third is an fully qualified names of the symbol. Disadvantage is that you have to type the fully qualified name everywhere you use the symbol.

Clearly, Second & Third are the more suitable ones. There is no performance difference in either of them. The only difference is the amount of characters you type in. Simply, choose either depending on what your coding standard specifies.

EDIT:
As @Jerry points out, using declaration in combination with ADL(Argument dependent lookup) can lead to undesirable effects.
You can find a detailed explanation in one of my answers:

Detailed explanation on how Koenig lookup works with namespaces and why its a good thing?

under the section,
Why the criticism of Koenig Algorithm?

like image 124
Alok Save Avatar answered Sep 27 '22 17:09

Alok Save


There is one (admittedly, somewhat uncommon) situation in which the form you use really can make a difference, and the form you want to use is using namespace foo, and it's most commonly applied to the std namespace (i.e., where you write using namespace std;.

The most obvious example is that you're writing a sort for a user-defined type. It's possible that this will be applied to a type for which the user has also defined their own swap.

You're stuck with a situation where you want to use their swap if they've defined one, but use std::swap if they haven't defined one. If you use std::swap directly in your code, then you'll end up using std::swap even if the type has a swap of its own defined. Conversely, your code will fail to compile if you directly specify a swap specifically for the type, and none has been supplied.

To get around this, you do something like:

using namespace std;

template <class Iter>
void my_sort(Iter first, Iter last) {
    // ...
    if (*last < *first)
        swap(*first, *last);
}

This will find the swap specifically for the type being compared (i.e., a swap defined in the same namespace as that type), if there is one (via argument dependent lookup), and std::swap if none is defined for the type (via the using namespace std;).

This can have an impact on performance -- if they've written a swap specifically for their type, you can generally expect that it's because by doing so, they can provide better performance. That means that explicitly specifying std::swap may work, but will probably lead to inferior performance.

Otherwise, it's almost entirely a matter of convenience and readability -- I mostly prefer giving the full names (e.g., std::swap) except in a situation like above, where (at the time that I'm writing the code) either of at least two possibilities might be preferred, and I want to give the compiler sufficient leeway to pick the right one.

The other time I find using declarations/directives useful is when namespaces get really deeply nested. Boost (for one obvious example) has some names that would be way too long for convenient use if you used the fully qualified name every time. This was especially true for the (now, thankfully, mostly obsolete) Boost Lambda library, where you used placeholders like _1, that would have ended up as something like boost::lambda::placeholders::_1 (but I'm going from memory, so that's probably at least partly wrong) if you insisted on using a fully qualified name. That would have defeated a large part of the purpose of using the lambda library in the first place.

like image 29
Jerry Coffin Avatar answered Sep 27 '22 17:09

Jerry Coffin