Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an inline function in a header file use a constant which has internal linkage?

Consider the following code:

const int a = 0;
const std::string b = "hi";

inline void f_a1()
{
    std::cout << a;
}

inline void f_b1()
{
    std::cout << b;
}

inline void f_a2()
{
    std::cout << &a;
}

inline void f_b2()
{
    std::cout << &b;
}

Assume this code exists in a header file that will be included in multiple translation units.

My understanding of inline functions is that they must be exactly the same in every translation unit.

My understanding of constants as used above, is that they are implictly static ie internal linkage. These means each translation unit gets its own copy.

As the inline functions above rely on these constants, which of these functions, if any, are correct?

like image 356
Neil Kirk Avatar asked Feb 27 '15 13:02

Neil Kirk


1 Answers

If included into multiple translation units, the only function that is valid is f_a1.

The relevant clause is [basic.def.odr]/6, which states that an inline function can appear in multiple translation units, but only given that:

[...] a name can refer to a non-volatile const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the object is not odr-used, and the object has the same value in all definitions of D;

As the objects are const, they have internal linkage per [basic.link]/3:

A name having namespace scope (3.3.6) has internal linkage if it is the name of [...]
— a non-volatile variable that is explicitly declared const or constexpr and neither explicitly declared extern nor previously declared to have external linkage [...]

However, taking the address of or forming a reference to a variable (e.g. for argument passing) is odr-use, so f_a2 and f_b2 are invalid. f_b1 is also invalid, as the ostream output operator for std::string takes its argument by reference; and even if it took its argument by value the implicitly called copy constructor would take its argument by reference. f_a1 is OK because the int stream-out operator takes its argument by value, and copying the value of an int const is not odr-use.

like image 181
ecatmur Avatar answered Oct 11 '22 10:10

ecatmur