Unnamed and inline namespaces in C++
Hey, guys today we are going to learn about unnamed(anonymous) and inline namespaces in C++. Before starting with the unnamed and inline namespaces, I would like to briefly discuss namespaces and translation units.
namespace and translation units
namespace: It is used to organize our code in different logical units which increases the understandability of code and prevents name collisions.
It is a block or declarative region which provides scope to identifiers. A particular namespace can be created and its elements can be accessed in 2 ways as shown below:
//creating namespace namespace name_of_namespace { //code of namespace int identifier_of_namespace=5; } int main() { //accessing elements of namespace using :: operator cout<<name_of_namespace::identifier_of_namespace ; /*accessing elements of namespace using "using namespace name_of_namespace"*/ using namespace name_of_namespace; cout<<identifier_of_namespace; return 0; }
Translation units: It is a basic unit of compilation in C++. It consists of a source file after it has been processed.
unnamed (anonymous ) namespace
It is a namespace without a name i.e. no name is given to it in its declaration statement. Just like static variables or static functions, unnamed namespace is used for declaring unique identifiers of a program. Memory is allocated to static members only when it is created and used for the lifetime of the program. The content of unnamed namespace is accessible to the enclosing namespace i.e It is treated as part of parent namespace. Identifiers declared in unnamed spaces have internal linkage which means they accessible within the translation unit in which it is created i.e their scope is limited to the local file. It is a lot easier to create and use unnamed namespace rather than declaring static identifiers repetitively. Moreover static is limited to variables and function and cant be used with user-defined datatypes like class and structure. Thus unnamed namespace is a preferable alternative of static.
Let’s understand more with the help of a given example:
#include <iostream> using namespace std; //use of unnamed namespace namespace { int cust_no; void hello() { cout<<"\nHello customer no"<<cust_no; } } int main() { cust_no=5; hello(); return 0; }
Output:
Hello customer no5
We declare unnamed namespaces i.e. we declare a namespace and don’t give a name to it.
namespace { printSomething() { cout << "Hello World!" << endl; } }
An unnamed namespace is also called an anonymous namespace. Identifiers declared in unnamed namespaces are treated as they are part of the global namespace. We can access them through the main function without a qualifier. We use an unnamed namespace to give internal linkage to all identifiers present in it. This means identifiers inside unnamed namespace can be accessed by codes of the same file. These identifiers can not be accessed by codes of other files.
inline namespace
Suppose we have a function already declared in a program and we want some changes in that function. One way to achieve this is to rewrite that function. But doing so may disrupt the overall program’s functionality.
Another way to achieve this is to write a different function with the desired functionality. But think each time writing a different function according to the desired functionality may end up program file with full of lots of functions.
So an alternative way to achieve this is by using inline namespaces. For inline namespaces, we use a keyword inline.
All the Identifiers which we declare inside inline namespaces are part of the parent namespace. So we can access identifiers of inline namespaces in the main function without qualifiers. Inline namespaces don’t give internal linkage to all its identifiers.
#include <iostream> inline namespace p1 // declare an inline namespace named p1 { void printSomething() { std::cout << "p1\n"; } } namespace p2 // declare a normal namespace named p2 { void printSomething() { std::cout << "p2\n"; } } int main() { p1::printSomething(); // calls the p1 printSomething() function p2::printSomething(); // calls the p2 printSomething() function printSomething(); // calls the inline version of printSomething() (which is p1) return 0; }
Output:
p1 p2 p1
Here in the above example, printSomething() function has been declared twice one inside the inline namespace and other inside normal namespace. Any of them can be the newer one.
To access identifiers of normal namespaces one needs to explicitly use qualifiers. But to access identifiers of inline namespaces one may or may not use qualifiers, they are treated as default one.
It was introduced in C++ 11. Like unnamed namespace, code/content of inline namespace is accessible to enclosing (parent) namespace. Thus inline namespace is transitive in nature. inline namespace is used for updating the version of an existing function/code. Let’s understand this with the help of an example. Consider the given code which is a basic code to print “Hello “.
#include <iostream> using namespace std; void hello() { cout<<"\nHello"; } int main() { hello(); return 0; }
Now Let’s assume that we have created a newer version of the function hello(). Before updating the function we must test it without disrupting the functioning of the existing version i.e. version_1. This can be done with the help of inline namespace. With the help of inline namespace the above code can be modified to the given below:
#include <iostream> using namespace std; inline namespace version_1 //creating inline namespace of existing version { void hello() { cout<<"\nHello "; } } namespace version_2 // creating a normal namespace for version 2 { int cust_no; void hello() { cout<<"\nHello "; cout<<"\nHave a good day "; } } int main() { hello();//this will call the existing version version_2::hello();/*this will call version 2 without interfering with existing version*/ return 0; }
Hello Hello Have a good day
In the above code, calling hello() will implicitly use version_1. For calling our new version i.e version_2 we have to explicitly call version_2 hello() by using :: operator(full name of hello).Refer line 23 of the above code. After the successful testing of version_2 we can make version_2 as inline as shown below:
#include <iostream> using namespace std; namespace version_1 //creating inline namespace of existing version { void hello() { cout<<"\nHello "; } } inline namespace version_2 // creating a normal namespace for version 2 { int cust_no; void hello() { cout<<"\nHello "; cout<<"\nHave a good day "; } } int main() { hello();//this will call the existing version version_1::hello();/*this will call version 1 without interfering with version2*/ return 0; }
Hello Have a good day Hello
Now the function hello() will implicitly call version_2 and if some users are unable to use the updated version they can call the older version. For calling the older version they need to explicitly call version_1 hello() like called in line 23 of the above code. Thus inline namespace is very helpful in updating code/functions in C++.
Also, refer
Leave a Reply