Book Image

Modern C++ Programming Cookbook

By : Marius Bancila
Book Image

Modern C++ Programming Cookbook

By: Marius Bancila

Overview of this book

C++ is one of the most widely used programming languages. Fast, efficient, and flexible, it is used to solve many problems. The latest versions of C++ have seen programmers change the way they code, giving up on the old-fashioned C-style programming and adopting modern C++ instead. Beginning with the modern language features, each recipe addresses a specific problem, with a discussion that explains the solution and offers insight into how it works. You will learn major concepts about the core programming language as well as common tasks faced while building a wide variety of software. You will learn about concepts such as concurrency, performance, meta-programming, lambda expressions, regular expressions, testing, and many more in the form of recipes. These recipes will ensure you can make your applications robust and fast. By the end of the book, you will understand the newer aspects of C++11/14/17 and will be able to overcome tasks that are time-consuming or would break your stride while developing.
Table of Contents (19 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Using unnamed namespaces instead of static globals


The larger a program the greater the chances are you could run into name collisions with file locals when your program is linked. Functions or variables that are declared in a source file and are supposed to be local to the translation unit may collide with other similar functions or variables declared in another translation unit. That is because all symbols that are not declared static have external linkage and their names must be unique throughout the program. The typical C solution for this problem is to declare those symbols static, changing their linkage from external to internal and therefore making them local to a translation unit. In this recipe, we will look at the C++ solution for this problem.

Getting ready

In this recipe, we will discuss concepts such as global functions, static functions, and variables, namespaces, and translation units. Apart from these, it is required that you understand the difference between internal and external linkage; that is key for this recipe.

How to do it...

When you are in a situation where you need to declare global symbols as statics to avoid linkage problems, prefer to use unnamed namespaces:

  1. Declare a namespace without a name in your source file.
  2. Put the definition of the global function or variable in the unnamed namespace without making them static.

The following example shows two functions called print() in two different translation units; each of them is defined in an unnamed namespace:

    // file1.cpp 
    namespace 
    { 
      void print(std::string message) 
      { 
        std::cout << "[file1] " << message << std::endl; 
      } 
    } 

    void file1_run() 
    { 
      print("run"); 
    } 

    // file2.cpp 
    namespace 
    { 
      void print(std::string message) 
      { 
        std::cout << "[file2] " << message << std::endl; 
      } 
    } 

    void file2_run() 
    { 
      print("run"); 
    }

How it works...

When a function is declared in a translation unit, it has external linkage. That means two functions with the same name from two different translation units would generate a linkage error because it is not possible to have two symbols with the same name. The way this problem is solved in C, and by some in C++ also, is to declare the function or variable static and change its linkage from external to internal. In this case, its name is no longer exported outside the translation unit, and the linkage problem is avoided.

The proper solution in C++ is to use unnamed namespaces. When you define a namespace like the ones shown above, the compiler transforms it to the following:

    // file1.cpp 
    namespace _unique_name_ {} 
    using namespace _unique_name_; 
    namespace _unique_name_ 
    { 
      void print(std::string message) 
      { 
        std::cout << "[file1] " << message << std::endl; 
      } 
    } 

    void file1_run() 
    { 
      print("run"); 
    }

First of all, it declares a namespace with a unique name (what the name is and how it generates that name is a compiler implementation detail and should not be a concern). At this point, the namespace is empty, and the purpose of this line is to basically establish the namespace. Second, a using directive brings everything from the _unique_name_ namespace into the current namespace. Third, the namespace, with the compiler-generated name, is defined as it was in the original source code (when it had no name).

By defining the translation unit local print() functions in an unnamed namespace, they have local visibility only, yet their external linkage no longer produces linkage errors since they now have external unique names.

Unnamed namespaces are also working in a perhaps more obscure situation involving templates. Template arguments cannot be names with internal linkage, so using static variables is not possible. On the other hand, symbols in an unnamed namespace have external linkage and can be used as template arguments. This problem is shown in the following example where declaring t1 produces a compiler error because the non-type argument expression has internal linkage. However, t2 is correct because Size2 has external linkage:

    template <int const& Size> 
    class test {}; 

    static int Size1 = 10; 

    namespace 
    { 
      int Size2 = 10; 
    } 

    test<Size1> t1; 
    test<Size2> t2;

See also

  • Using inline namespaces for symbol versioning