Global variables

One of the biggest limitations with header-only libraries is that, prior to C++17, there was no way to create global variables. Although global variables should be avoided whenever possible, there are situations where they are needed. To demonstrate this, let's create a simple API that outputs to stdout as follows:

#ifndef MY_LIBRARY
#define MY_LIBRARY

#include <iostream>
#include <iomanip>

namespace library_name
{
void my_api(bool show_hex = false)
{
if (show_hex) {
std::cout << std::hex << "The answer is: " << 42 << ' ';
}
else {
std::cout << std::dec << "The answer is: " << 42 << ' ';
}
}
}

#endif

The preceding example creates an API that will output to stdout. If the API is executed with true instead of the default false, it will output integers in hexadecimal instead of decimal format. In this example, the change from decimal to hexadecimal is really a configuration setting in our library. Without global variables, however, we would have to resort to other mechanisms to make this work, including macros or, in the preceding example, function parameters; the latter choice is even worse as it couples the configuration of the library to its API, which means any additional configuration options would alter the API itself.

One of the best ways to address this is to use global variables in C++17, as follows:

#ifndef MY_LIBRARY
#define MY_LIBRARY

#include <iostream>
#include <iomanip>

namespace library_name
{
namespace config
{
inline bool show_hex = false;
}

void my_api()
{
if (config::show_hex) {
std::cout << std::hex << "The answer is: " << 42 << ' ';
}
else {
std::cout << std::dec << "The answer is: " << 42 << ' ';
}
}
}

#endif

As shown in the preceding example, we added a new namespace to our library called config. Our API no longer needs any parameters and determines how to function based on an inline global variable instead. Now, we can use this API as follows:

#include "my_library.h"
#include <iostream>

int main(void)
{
library_name::my_api();
library_name::config::show_hex = true;
library_name::my_api();

return 0;
}

The results in the following output:

It should be noted that we placed the configuration setting in a config namespace to ensure that our library's namespace isn't polluted with name collisions, which ultimately ensures that the intent of the global variable is obvious.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset