Search code examples
c++inlinetranslation-unit

Why does defining inline global function in 2 different cpp files cause a magic result?


Suppose I have two .cpp files file1.cpp and file2.cpp:

// file1.cpp
#include <iostream>

inline void foo()
{
    std::cout << "f1\n";
}

void f1()
{
    foo();
}

and

// file2.cpp
#include <iostream>

inline void foo()
{
   std::cout << "f2\n";
}

void f2()
{
    foo();
}

And in main.cpp I have forward declared the f1() and f2():

void f1();
void f2();

int main()
{
    f1();
    f2();
}

Result (doesn't depend on build, same result for debug/release builds):

f1
f1

Whoa: Compiler somehow picks only the definition from file1.cpp and uses it also in f2(). What is the exact explanation of this behavior?.

Note, that changing inline to static is a solution for this problem. Putting the inline definition inside an unnamed namespace also solves the problem and the program prints:

f1
f2

Solution

  • This is undefined behavior, because the two definitions of the same inline function with external linkage break C++ requirement for objects that can be defined in several places, known as One Definition Rule:

    3.2 One definition rule

    ...

    1. There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14),[...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

    6.1 each definition of D shall consist of the same sequence of tokens; [...]

    This is not an issue with static functions, because one definition rule does not apply to them: C++ considers static functions defined in different translation units to be independent of each other.