inline variable in c++17

1, Introduction to inline

It is estimated that anyone who has studied c + + knows the keyword inline. In the application of functions, there is the use of inline functions (for specific usage, please refer to the previous articles, which will not be expanded here). Inline function ensures that the function has the same copy in each compilation unit. The method of sacrificing code in exchange for time overhead must impress everyone. Then, some people will ask, "is there an inline variable?", indeed, this inline variable is introduced in c++17. Why the inline variable is needed is related to some practical applications of c + +.
Generally speaking, the programming of any language should try to maintain the consistency of style and thought, even if there may be no small differences in these functions. However, in the application of c + +, the initial definition and initialization of global variables and class static member variables (non const) always maintain a routine that is inconsistent with other variables, and this routine will naturally increase the learning cost. These small learning costs continue to accumulate, forming a general understanding of c + + "this thing is too difficult"!
Next, analyze the inline keyword from the perspective of static internal member variables.

2, Common usage of static members in c + +

Let's take a look at the declaration and definition of static variables of class members before c++17:

//student.h
class Student{
public:
    Student(char *name);
   
public:
    static int total_;  //Static member variable
private:
    char * name_;
};
//student.cpp

#include "student.h"
int Student::total_ = 0;//It is recommended to define in cpp

int main()
{
  Student::total_ = 100;
  std::cout<<"Student total is:"<<Student::total_<<std::endl;
  return 0;
}

Before C + + 11, this did not seem to be a big problem. After all, all class member variables are not allowed to be directly initialized in the class declaration. However, after c++11, the member variables of common classes can be initialized directly in class declarations, while static member variables (except const static) still continue to inherit the old inherent application methods. As the saying goes, if there is a demand, there will be changes. c++17 adds a keyword inline to it to realize the homogenization operation. In this way, it is easy to learn and remember.

3, New usage in c++17

Let's look at the usage under the new standard:

Global variables:

Header file "example.h":

#ifndef EXAMPLE_H
#define EXAMPLE_H
#include <atomic>
// function included in multiple source files must be inline
inline int sum(int a, int b)
{
    return a + b;
}
// variable with external linkage included in multiple source files must be inline
inline std::atomic<int> counter(0);
#endif
Source file #1:

#include "example.h"
int a()
{
    ++counter;
    return sum(1, 2);
}
Source file #2:

#include "example.h"
int a() // yet another function with name `a`
{
    ++counter;
    return sum(3, 4);
}
 
int b()
{
    ++counter;
    return sum(5, 6);
}

Static variables:

struct X
{
    inline static int n = 1;
};

In c++17, constexpr and thread can be combined_ Together with local, you can also achieve the purpose of unified style:

1,constexpr

//c++17 front
struct D
{
    static constexpr int n = 5;
};
//After C++17
struct D
{
    inline static constexpr int n = 5;
};

The above two definitions are basically equivalent. In other words, constexptr is equivalent to inline in c++17. However, if you use references or addresses before c++17, you still need to use constexpr int D:: n in the compilation unit (cpp file); How this type is defined.

2,thread_local

//Before C++17, it was applied in a single CPP compilation unit
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
 
thread_local unsigned int rage = 1; 
std::mutex cout_mutex;
 
void increase_rage(const std::string& thread_name)
{
    ++rage; // modifying outside a lock is okay; this is a thread-local variable
    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "Rage counter for " << thread_name << ": " << rage << '\n';
}
 
int main()
{
    std::thread a(increase_rage, "a"), b(increase_rage, "b");
 
    {
        std::lock_guard<std::mutex> lock(cout_mutex);
        std::cout << "Rage counter for main: " << rage << '\n';
    }
 
    a.join();
    b.join();
}
//After c++17, it can be used in multiple compilation units by using inline

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
 
inline thread_local unsigned int rage = 1; 
//The code below is the same

In fact, from the above application, we can see that the inline variable introduced by c++17 also uses the relevant principles of inlining, mainly to avoid violating the ODR principle (single definition rule) during c + + compilation. In addition, it should be noted that when the static class member variable is its own type, it still needs to use the early definition method. Do not use inline as an inline variable to define usage.

  • The code mainly comes from https://en.cppreference.com/w/cpp/language/static#Static_data_members

4, Summary

The introduction of the new c + + standard is getting faster and faster, and the support of the compiler can't keep up with it. In other words, after reading the standard documents, most beginners are really uncertain about the compilation environment. But this does not affect the idea of learning new standards and broadening our horizons. The new visual studio 2022 will be launched soon. It is estimated that the support for c++20 must be very full. I am looking forward to it!

Keywords: C++ Back-end C++11

Added by pcjackson06 on Sat, 06 Nov 2021 13:29:46 +0200