What is the correct way to define inline functions?

Let's say I have class X (Xh):

class X { private: unsigned unitsSold = 0; double revenue = 0.0; public: double avgPrice(); } 

How should avgPrice() be defined?

Option 1 (in class):

Xh

 class X { private: unsigned unitsSold = 0; double revenue = 0.0; public: double avgPrice() { return unitsSold ? revenue / unitsSold : 0; } } 

Option 2 (in the same file as the class, but outside the class definition):

Xh

 class X { private: unsigned unitsSold = 0; double revenue = 0.0; public: double avgPrice(); } inline double X::avgPrice() { return unitsSold ? revenue / unitsSold : 0; } 

or Option 3 (in a separate header file):

Xh:

 class X { private: unsigned unitsSold = 0; double revenue = 0.0; public: double avgPrice(); } 

X-inl.h:

 #include "Xh" inline double X::avgPrice() { return unitsSold ? revenue / unitsSold : 0; } 
+4
source share
6 answers

There may have been some misunderstanding regarding the value of the inline specifier. Yes, this gives a hint to the compiler that it would be preferable to embed the code instead of making a call, but the compiler is not forced to obey this hint. The main use of the inline specifier is to avoid breaking the rules of one definition .

Once you declare an inline function, it must be defined in each translation unit used, and the definition must be exactly the same every time. This is the opposite of what your title suggests - choosing where you define the function indicates whether it should be marked inline or not.

1) and 2) in order. In the first case, it is implicitly inline , and in the second you explicitly declared it like this. The definition is the same everywhere you include the title.

Case 3) will only work if you compile and merge X_impl.h as the source file. In this case, there will be only one definition, and inline will be redundant. Thus, the compiler does not see the definition in other translation units, and this makes its built-in function impossible, regardless of whether it is inline or not.

If the purpose of X_impl.h was to reduce the visual size of the header, then you should do it the other way around, include it at the end of Xh . inline should remain in this case.

+6
source

All three options are correct.

After that it depends:

  • If your function is fairly short (e.g. getters / seters), the function defined in the class definition is more common.

  • If your function is larger, it may be useful to define it in a different header and include only that header in the source in which the function is used. This will speed up your compilation. But this is rarely a big inline function.

But do not forget that this is not because you used the inline , which your compiler will embed in your function. It is up to the compiler to decide whether it will work anywhere or not.

This is explicitly stated in the standard:

7.1.2 / 2 Function Specifiers [dcl.fct.spec]

Declaring a function using the inline specifier declares an inline function. The inline specifier indicates the implementation that the built-in substitution of the function body at the call point is preferable to the usual function call mechanism. An implementation is not required to perform this built-in lookup at the dial peer ; however, even if this built-in substitution is omitted, other rules for built-in functions defined in 7.1.2 must still be followed.

Last thing:

Most compilers already optimize the code to generate built-in functions when it is more convenient. This specifier tells only the compiler that inline is preferred for this function.


As pointed out by jrok, inline used primarily to avoid violating the One Definition rule. Here we can also quote a small part of the standard:

(§ 7.1.2 / 4) An inline function must be defined in each translation unit in which it is odr-used , and must have exactly the same definition in each case (3.2).

3.2 One definition rule [basic.def.odr]

No translation unit should contain more than one definition of any variable, function, class type, enumeration type or template.

+1
source

I would choose every method that is readable, and it depends on the size of the function:

  • single line functions -> option 1,
  • small functions → option 2,
  • medium-sized functions → option 3,
  • large function → are you sure you want to embed?

If you have a large number of small functions, go to option 3 and never mix options 2 and 3 together.

In addition, since you presented your third option, you will need to remember X-inl.h instead of Xh . If you change the following:

Xh:

 #ifndef _CLASS_X_H_ #define _CLASS_X_H_ class X { private: unsigned unitsSold = 0; double revenue = 0.0; public: double avgPrice(); }; #include "X-inl.h" #endif 

X-inl.h:

 inline double X::avgPrice() { return unitsSold ? revenue / unitsSold : 0; } 

Then you can enable Xh as usual.

+1
source

It depends on where you use the built-in function and how often you use it. If the code of the built-in function is short (as for most getters / setters), and if it is (probably) used in many places, then directly defining the class is an easy way.

If your built-in function is massive and is used only by a few users of your class, it is best to use it in a separate header. This speeds up compilation in cases where an inline string is not required, but requires that you provide this additional header file to your library users.

0
source

I suppose there might be a little confusion over the inline and the inline function / method.

The inline tells the compiler that it must copy the function / method code to the place where the function / method is called. Example:

 /* [...] */ inline void sayHello() { std::cout << "Hello" << std::endl; } int main(int argc, char **argv) { sayHello(); return 0; } 

will become

 /* [...] */ int main(int argc, char **argv) { std::cout << "Hello" << std::endl; return 0; } 

when compiling. But the compiler is not forced to inline the function / method.

On the other hand, the built-in method is implemented in the place where you declare it. Example:

 /* [...] */ class X { private: unsigned int unitsSold; double revenue; public: /* [...] */ double avgPrice() { if (unitsSold == 0) { return 0.0; } return revenue/unitsSold; } }; 
0
source

As you add the inline clause to the compiler, the three options you provide will (should) result in the same compiled code.

It always considers a standard compiler performing a standard compilation task ...

-one
source

Source: https://habr.com/ru/post/1496720/


All Articles