Namespaces
The code inside a namespace should be in the same nesting level as the namespace.
Example
#include <iostream>
#include <cstdint>
#include <utility>
#include <string>
#include <memory>
namespace person
{
template<typename T>
using Name = std::unique_ptr<T>;
template<typename T>
using Age = std::unique_ptr<T>;
template<typename T1, typename T2>
class Person
{
private:
// Private Members
Name<T1> name;
Age<T2> age;
public:
// Constructors
template<typename U1, typename U2>
Person(U1&& name, U2&& age);
// Public Methods
// Element Access
T1 const& get_name();
T2 const& get_age();
// Operators
template<typename _T1, typename _T2>
friend std::ostream& operator<<(std::ostream& os, Person<_T1,_T2> const& p);
};
//
// Constructors
//
template<typename T1, typename T2>
template<typename U1, typename U2>
Person<T1,T2>::Person(U1&& name, U2&& age)
: name(std::make_unique<
typename Name<T1>::element_type>(std::forward<U1>(name)))
, age(std::make_unique<
typename Age<T2>::element_type>(std::forward<U2>(age)))
{
}
//
// Public Methods
//
template<typename T1, typename T2>
T1 const& Person<T1,T2>::get_name()
{
return *(this->name);
}
template<typename T1, typename T2>
T2 const& Person<T1,T2>::get_age()
{
return *(this->age);
}
//
// Operators
//
template<typename _T1, typename _T2>
std::ostream& operator<<(std::ostream& os, Person<_T1,_T2> const& p)
{
std::cout << "Name: " << *(p.name) << std::endl;
std::cout << "Age: " << *(p.age);
return os;
}
} // namespace person
int main(int argc, char const* argv[])
{
using Person = person::Person<std::string, int16_t>;
std::string name_augustine = "augustine";
Person augustine{name_augustine, 33};
Person mary{"mary", 42};
std::cout << mary << std::endl;
std::cout << augustine << std::endl;
return 0;
}
Structuring your namespaces
All the namespaces names should be in the singular form.
Consider the following project structure:
- anastasia
| - include
| | - CMakeLists.txt
| | - anastasia
| | | - component-a.hpp
| | | - component-a
| | | | - algorithm.hpp
| | | | - enumeration.hpp
| | | - component-b.hpp
| | | - component-b
| | | | - binary-tree.hpp
| | | | - data-structure.hpp
| - extern
| - doc
| - test
| - CMakeLists.txt
The approach taken to minimize name collision, is to follow the directory structure of your project.
Now, how does that work?
The top level file
Lets consider the file component-a.hpp, it is in the top level of the anastasia project source files. Therefore, it should use the namespace equivalent to its name in the snake_case format.
Example
The example below illustrates the contents of the component-a.hpp file.
namespace component_a
{
// Functionalities
} // namespace component_a
Reiterating, the namespace is the source filename converted, to the snake_case format
Does the namespace name has to be grammatically equivalent to the class name?
That is true for the top level source file. This simplifies the access to a functionality, given a namespace, you know how to access it in a more natural way.
What about the components/functionalities of your class?
This will the discussed below.
The components/functionalities
Now lets consider one of the source files of the component-a folder.
The component-a folder represents the implementations of component-a.hpp functionalities/components.
The methodology for naming the namespace is the same as of the top level source file, i.e., use the filename. Only this time, you are representing a functionality/component of your top level source file, so it should be nested within the namespace of the top level source file.
Example
Give the component-a/algorithm.hpp file, the namespace should be structured as follows:
namespace component_a::algorithm
{
} // namespace component_a::algorithm
Notice that, in both examples, the namespace ends with a comment that uses the namespace keyword, and follows by repeating the namespace identifier. This is a good practice to avoid accidentally erasing the namespace closing bracket.