Multiple definitions of inline function

In C++, a function is annotated with inline to implore the compiler to inline that function’s code into its callers. The C++ standard says that injecting multiple differing definitions of an inline function into a program is illegal because it breaks the ODR.

For example, ยง7.1.2 from the C++11 standard says:

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case.

So, having multiple differing definitions is illegal but the compiler cannot really stop it. This is because two differing definitions of the same inline method might be inlined into their callers in two different compilation units that are linked together into a program.

Thus, if we use multiple different inline definitions, all bets are off and it is undefined behavior.

This example illustrates the final behavior differs based on just compilation flags:

// x.cpp
#include <iostream>

inline void f()
{
    std::cout << __FILE__ << std::endl;
}

extern void g();

int main()
{
    f();
    g();

    return 0;
}

// y.cpp
#include <iostream>

inline void f()
{
    std::cout << __FILE__ << std::endl;
}

void g()
{
    f();
}

$ g++ x.cpp y.cpp
$ ./a.out
x.cpp
x.cpp

$ g++ -O2 x.cpp y.cpp
$ ./a.out
x.cpp
y.cpp

If we want to control and want each caller to only use its local inline definition, then we can do that by placing the inline method inside an anonymous namespace. The practice of multiple differing inline definitions is still illegal, but at least we now have controlled what happens. This example illustrates this:

// x.cpp
#include <iostream>

namespace
{
inline void f()
{
    std::cout << __FILE__ << std::endl;
}
}

extern void g();

int main()
{
    f();
    g();

    return 0;
}
                                                                                                                                                                                // y.cpp
#include <iostream>

namespace
{
inline void f()
{
    std::cout << __FILE__ << std::endl;
}
}

void g()
{
    f();
}

$ g++ x.cpp y.cpp
$ ./a.out
x.cpp
y.cpp

$ g++ -O2 x.cpp y.cpp
$ ./a.out
x.cpp
y.cpp

Thanks to Arch for the elegant examples.

Advertisements

2 thoughts on “Multiple definitions of inline function

  1. “If we want to control and want each caller to only use its local inline definition” then we can use good old “static” keyword from classic c. If we add “static” before inline function definition then effect is the same as with anonymous namespace. And it is good practice to keep local (per compilation unit) functions static.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.