Overview
In large projects, multiple classes can share same name, which can lead to compilation errors and confusion. namespace can be used to modularise them in separately to avoid overlapping.
typedefs are commonly used provide an alias to a type. However it has some limitations when used in templates. In C++ 11, using keyword is introduced to overcome these limitations also extend its functionality.
Details
namespace
Consider following code. Here the class circle is defined in two different header files. This leads to compilation errors.
//regions struct circle{string address();}; //geometry.h namespace geometry { struct circle{void draw();}; } //trigonometry.h namespace trigonometry { struct circle {double area();}; } geometry::circle c; //OK trigonometry::circle c2; //OK ::circle c3; //OK global namespacecircle c4; //NOT OK ambiguous scope
scoping is applied using :: in front of namespace. :: without namespace represents global namespace.
This is depicted in the example 19.
namespaces are open. New types can be added to it. Also alias can be created for namespaces with long names.
//geometry.h namespace geometry {struct circle {};} //sphere.h namespace geometry {struct sphere {};}namespace geo = geometry; //alias for geometry geo::circle c; //geometry::circle geometry::sphere s;
This is depicted in the example 20.
namespaces can be nested.
namespace shapes { namespace round { struct circle {}; } namespace rect { struct square{}; } } using namespace shapes; round::circle c; //shapes::round::circle rect::square s; //shapes::rect::square
This is depicted in the example 21.
namespaces can be used for versioning using inline namespaces.
namespace shapes { inline namespace ver3_0 { struct circle {}; } namespace ver2_0 { struct circle {}; }namespace ver1_0 { struct circle {}; }} using namespace shapes; circle c; //shapes::ver3_0::circle
This is depicted in the example 22.
nameless namespaces can be used to use types private to a translation unit. Internally compiler adds a unique name to the namespace. Notice that using is not required.
//a.cpp namespace { struct circle {}; } circle a; //becomes QSx5Me43PV402gA::circle //b.cpp namespace { struct circle {}; } circle a; //becomes ognslFYviYUnkks::circle
using
namespaces are associated with using declaration and directive.
using directive
using declaration merges contents of a namespace into the global namespace. In the following example, all the types of geometry namespace are merged into global namespace. Thus circle c4; declaration is same as geometry::circle c4;
//geometry.h namespace geometry { struct circle{void draw();}; } //trigonometry.h namespace trigonometry { struct circle {double area();}; }using namespace geometry; geometry::circle c; //OK trigonometry::circle c2; //OK circle c4; //OK same as geometry::circle
This is depicted in the example 23.
using declaration
Sometimes it could be overwhelming to include entire namespace. In such cases it's possible to include a type as shown below.
using std::cout; using std::endl; cout << "hello, World!" << endl;
Note that using declaration and directive can be used globally or only to a local scope.
using namespace std; //global scope //geometry.h namespace geometry {struct circle {};} //trigonometry.h namespace trigonometry {struct circle {};} void driver() { using namespace geometry; //local to function circle c; //geometry::circle }
This is depicted in the example 24.
using can be used to access overloaded base class functions in the derived class. This is captured in the example below. Here the derived class Y2 retrieves overloaded print function from the base class.
struct X { void print(int){} }; struct Y: public X { void print(double){} }; struct Y2: public X { using X::print; //brings base class versions of print void print(double){} }; Y y; y.print(1); //calls print(double) Y2 y2; y2.print(1); //calls overloaded print(int)
This is depicted in the example 25.
The above can be extended to intializer_list based constructor as well as shown in the example below.
function from the base class.
struct X
{X(int) {} X(initializer_list<int>) {} }; struct Y :public X { }; struct Z :public X { using X::X; }; Y y{1}; //OK calls X(int) Y yy{1,2,3}; //error Z z{1}; //OK calls X(int) Z zz{1,2,3}; //OK calls X(initializer_list<int>)
This is depicted in the example 26.
using can be used to define type alias in template definitions as well as shown in the type traits of an iterator.
/* template<typename Iterator> struct iterator_traits { using difference_type = typename Iterator::difference_type; using value_type = typename Iterator::value_type; using pointer = typename Iterator::pointer; using reference = typename Iterator::reference; using iterator_category = typename Iterator::iterator_category; }; */ array<int,10> a; auto itr = a.begin(); //reference to the first element iterator_traits<decltype(itr)>::reference b = *itr; //int& b = 100; //*itr == 100;
This is depicted in the example 27.
The following example demonstrates declaring alias templates and more.
// type alias, identical to // typedef std::ios_base::fmtflags flags; using flags = std::ios_base::fmtflags; // the name 'flags' now denotes a type: flags fl = std::ios_base::dec; // type alias, identical to // typedef void (*func)(int, int); using func = void (*) (int, int); // the name 'func' now denotes a pointer to function: void example(int, int) {} func f = example; // alias template template<class T> using ptr = T*; // the name 'ptr<T>' is now an alias for pointer to T ptr<int> x; // type alias used to hide a template parameter template<class CharT> using mystring = std::basic_string<CharT, std::char_traits<CharT>>; mystring<char> str; // type alias can introduce a member typedef name template<typename T> struct Container { using value_type = T; }; // which can be used in generic programming template<typename ContainerT> void info(const ContainerT& c) { typename ContainerT::value_type T; std::cout << "ContainerT is `" << typeid(decltype(c)).name() << "`\n" "value_type is `" << typeid(T).name() << "`\n"; } // type alias used to simplify the syntax of std::enable_if template<typename T> using Invoke = typename T::type; template<typename Condition> using EnableIf = Invoke<std::enable_if<Condition::value>>; template<typename T, typename = EnableIf<std::is_polymorphic<T>>> int fpoly_only(T) { return 1; } struct S { virtual ~S() {} }; Container<int> c;// prints ContainerT is `struct Container<int>`
// value_type is `int`
info(c); // Container::value_type will be int in this function // fpoly_only(c); // error: enable_if prohibits thisS s; fpoly_only(s); // okay: enable_if allows this