Lei Mao bio photo

Lei Mao

Machine Learning, Artificial Intelligence, Computer Science.

Twitter Facebook LinkedIn GitHub   G. Scholar E-Mail RSS

Introduction

With the inline specifier, the compiler would compile our program and make it run faster. However, when we tried to separate the declaration and definition to header and source files, sometimes the inline specifier would cause compile problems.


In this blog post, I documented the best practice of creating inline functions for programs.

Example

The following example has the library header file foo.h, the library source file foo.cpp, the main program source file main.cpp, and the CMake file CMakeLists.txt. We would like to make some of the functions or methods inline.

Code Files

foo.h

class Foo
{
public:
    int add(int x, int y);
    int minus(int x, int y);
};

int multiply(int x, int y);

foo.cpp

#include "foo.h"

int Foo::add(int x, int y)
{
    return x + y;
}

int Foo::minus(int x, int y)
{
    return x - y;
}

int multiply(int x, int y)
{
    return x * y;
}

main.cpp

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

int main()
{
    Foo foo;
    int x{1};
    int y{2};

    int sum{foo.add(x, y)};
    std::cout << "The sum of " << x << " and " << y << ":" << std::endl;
    std::cout << sum << std::endl;

    int difference{foo.minus(x, y)};
    std::cout << "The difference of " << x << " and " << y << ":" << std::endl;
    std::cout << difference << std::endl;

    int product{multiply(x, y)};
    std::cout << "The product of " << x << " and " << y << ":" << std::endl;
    std::cout << product << std::endl;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.13.0)

project(INLINE_TEST VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)

add_library(foo STATIC foo.cpp)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE foo)

Build

$ mkdir build
$ cd build
$ cmake ..
$ make

Incorrect Inline Method

To make the function inline, if we add inline to the beginning of either the function declaration or the function definition in either foo.h or foo.cpp. When we compile the program, we would get the linker error:

$ make
Scanning dependencies of target foo
[ 25%] Building CXX object CMakeFiles/foo.dir/foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
[ 75%] Linking CXX executable main
CMakeFiles/main.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x176): undefined reference to `multiply(int, int)'
collect2: error: ld returned 1 exit status
CMakeFiles/main.dir/build.make:84: recipe for target 'main' failed
make[2]: *** [main] Error 1
CMakeFiles/Makefile2:109: recipe for target 'CMakeFiles/main.dir/all' failed
make[1]: *** [CMakeFiles/main.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

Correct Inline Method

The correct inline method is to move the definition of the functions that we would like to inline to the header.


foo.h

class Foo
{
public:
    inline int add(int x, int y)
    {
        return x + y;
    }
    int minus(int x, int y);
};

inline
int multiply(int x, int y)
{
    return x * y;
}

foo.cpp

#include "foo.h"

int Foo::minus(int x, int y)
{
    return x - y;
}

References