How do you correctly define entities within a namespace that have been declared in a header?
Asked Answered
F

6

118

Consider a pair of two source files: an interface declaration file (*.h or *.hpp) and its implementation file (*.cpp).

Let the *.h file be like the following:

namespace MyNamespace {
  class MyClass {
  public:
    int foo();
  };
}

I have seen two different practices for using namespaces in source files:

*.cpp showing practice #1:

#include "MyClass.h"
using namespace MyNamespace;

int MyClass::foo() { ... }

*.cpp showing practice #2:

#include "MyClass.h"
namespace MyNamespace {

  int MyClass::foo() { ... }

}

My question: Are there any differences between these two practices and is one considered better than the other?

Focal answered 30/5, 2012 at 12:45 Comment(4)
There's also option 3: Just us the full name, e.g. int MyNamespace::MyClass::foo() ....Unwept
Possible duplicate: #7789663Cis
@Dave not duplicate. These questions complement each other. Recommend to add the link provided by Dave as "Read also..." to this question. My question will help novices to choose the correct style.Focal
Possible duplicate: #8211435Dextrorotation
F
86

From a code readability standpoint, it is probably better in my opinion to use the #2 method for this reason:

You can be using multiple namespaces at a time, and any object or function written below that line can belong to any of those namespaces (barring naming conflicts). Wrapping the whole file in a namespace block is more explicit, and allows you to declare new functions and variables that belong to that namespace within the .cpp file as well

Fictitious answered 30/5, 2012 at 12:52 Comment(6)
The question Dave linked in his comment to your question also outlines some key points in the differences (if any) between the two methods you're looking atFictitious
Guys, I really do not know whose answer to select. They have intersection while complement each other.Focal
Just commenting to acknowledge that some IDE's like CLion will only detect implementations if you use option/practice #2.Silvan
@PedroTanaka is this still the case? I have not noticed any such problem.Holograph
@JMcF I haven't checked since the time I published the comment. In early versions of Clion the problem occurred.Silvan
The option 3 presented below int MyNamespace::MyClass::foo() {...} is working correctly in CLion 2020.2.1Leto
D
65

The clearest is the option you didn't show:

int MyNamespace::MyClass::foo()
{
    //  ...
}

It's also very verbose; too much so for most people. Since using namespace is a recipe for name conflicts, at least in my experience, and should be avoided except in very limited scopes and places, I generally use your #2.

Dey answered 30/5, 2012 at 13:30 Comment(1)
Guys, I really do not know whose answer to select. They have intersection while complement each other.Focal
H
12

Are there any differences between these two practices

Yes. #1 and #2 are examples of a using-directive and a namespace definition respectively. They are effectively the same in this case but have other consequences. For instance, if you introduce a new identifier alongside MyClass::foo, it will have a different scope:

#1:

using namespace MyNamespace;
int x;  // defines ::x

#2:

namespace MyNamespace {
  int x;  // defines MyNamespace::x
}

is one considered better than the other?

#1 Pros: a little more terse; harder to accidentally introduce something into MyNamespace unwittingly. Cons: may pull in existing identifiers unintentionally.

#2 Pros: more clear that definitions of existing identifiers and declarations of new identifiers both belong to MyNamespace. Cons: easier to unintentionally introduce identifiers to MyNamespace.

A criticism of both #1 and #2 is that they are referring to an entire namespace when you probably only care about the definition of members of MyNamespace::MyClass. This is heavy-handed and it communicates the intent poorly.

A possible alternative to #1 is a using-declaration which includes only the identifier you're interested in:

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }
Holograph answered 1/6, 2016 at 20:57 Comment(0)
O
7

I'd like also to add that if you decide due to some reason to implement a template specialization in a cpp file and just rely on using namespace you will run into the following problem:

// .h file
namespace someNameSpace
{
  template<typename T>
    class Demo
    {
      void foo();
    };
}

// .cpp file
using namespace someNameSpace;

template<typename T>
void Demo<T>::foo(){}

// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo(){}

Otherwise if you apply #2 method this will be fine.

Opuntia answered 4/6, 2016 at 12:26 Comment(0)
D
4

I'd like to add one more way, using a using-declaration:

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }

This saves you from typing the namespace name many times, if a class has many functions.

Doughman answered 7/12, 2016 at 6:39 Comment(0)
C
1

I think the practice #1 is not correct C++ code at all. This code snippet defines ::MyClass::foo symbol, where the real full qualified name is ::MyNamespace::MyClass::foo.

To learn about namespaces you can read section 7.3 of the draft let's say for standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf

This concept is pretty old from 1998 or so, so you can use any standard or books of B.Stroustroup to learn about it.

In C++ language the namespace is a named scope. The namespace, as opposed to the class definition, is open to adding new functions to it.

The construction "using namespace NS;" in C++ is called as using-directive, and it can be used for several goals in my practice:

  1. You can use this directive in another namespace to combine(mix) names from a different namespace.
  2. In the context of the compilation unit it appends synonyms to all variables in namespace NS.

To define symbol, you can use two mechanisms - you can use the explicit qualification with all namespaces via operating in global namespace in C++ source file.

Or You can open namespace and add definitions to it (practice #2).

Cantilena answered 21/8, 2021 at 15:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.