Meaning of multiple definitions for inline or constexpr function - c++

This is my knowledge about function declaration and definition. If there is anything wrong, please correct me.
// Function Declaration
// This is usually put in .h header file
int occur (const char* sentence, const char& achar);
// Function Definition
// This is usually put in .cpp
int occur (const char* sentence, const char& achar) { // do job and return }
I am reading the "C++ Primer 5th Edition". Under "inline and constexpr functions # Chapter 6.5.2 P.240", it says
Unlike other functions, inline and constexpr functions may be defined
multiple times in the program.
I come up with something like this in my head:
// function delcaration .h file
constexpr int returnfour();
// function definition in .cpp file
constexpr int returnfour () { return 4; }
constexpr int returnfour () { return 4; }
Is it correct to have multiple definitions like this? What does defined multiple times in the program mean and when does someone want to do it?

Unlike other functions, inline and constexpr functions may be defined multiple times in the program.
Say you have a.h:
inline int foo() { return 10; }
constexpr int bar() { return 20; }
Now, you #include the file in couple of .cpp files.
file1.cpp:
#include "a.h"
// ... other functions
file2.cpp:
#include "a.h"
// ... other functions
int main() { return 0; }
When you compile those files, the functions foo and bar are defined in the object code of file1.cpp as well as the object code of file2.cpp. When you link those object code to create an executable, there are two definitions each of foo and bar. This is legal.
However, you are not allowed to have multiple definitions of the same inline function or constexpr function in the same compilation unit.
Using:
inline int foo() { return 10; }
inline int foo() { return 10; }
or
constexpr int bar() { return 20; }
constexpr int bar() { return 20; }
in a single cpp file is not legal.

A function declaration provides information to the compiler about the function's name, the number and type of arguments it accepts, and its return value. The compiler uses this information to check statements that attempt to call the function.
A function definition is a specific type of declaration that also includes a compound statement that implements the function (the part between the { and } of the function body).
The statement about inline and constexpr functions having more than one definition does not mean that the definition can be repeated multiple times in a single compilation unit. C++ has a separate compilation model, so the compiler does not have visibility of function definitions in one compilation unit when compiling another. However, multiple compilation units can each define an inline or constexpr function (e.g. by each #includeing the same header). The results - for the program as a whole - are undefined if different compilation units have non-equivalent definitions of the same function. A result of this is that the code for constexpr and inline functions may be duplicated within the program (e.g. inlined in multiple places, not inlined but implemented locally within an object file in a manner that is not visible to other compilation units, etc) and it is up to the compiler (usually working with other parts of the build chain) to ensure this happens in a consistent manner across compilation units.

As mentioned above inline and constexpr functions can be defined multiple times. But they should be only defined only once in each compilation units. By extension if you define them in the header and include the header in multiple compilation units they can be only defined once in the header file. NOTE: They should also have the same signature otherwise the behavior is undefined.
Both inline functions and constexpr functions are resolved at compile time and that is the reason it is possible to have multiple definitions across compilation units as long as you don't violate the ODR(one definition rule) within the compilation unit.
Please see the relevant excerpts from the C++ standard document:
7.1.5 The constexpr specifier
constexpr functions and constexpr constructors are implicitly
inline functions (7.1.2).
3.2 One-definition rule
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found
in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.

Related

Why is constexpr solving duplicated definition?

I have a header file where string are defined as static global.
namespace space {
#define NAME(P) static std::string const s_##P = #P
NAME(foo); NAME(bar); //... other values
#undef NAME
}
In another header, an enum is defined and a template specialization provides the mapping between the enum and a string in space.
enum class letter { alpha, beta };
template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> std::string const & mapping<letter::P1>() { return space::s_##P2; }
MAPPING(alpha,foo)
MAPPING(beta,bar)
#undef MAPPING
The above code doesn't link when the header is included in more than one translation unit because the specializations definitions do not match - due to global redefinition per translation unit (I guess).
Wrapping the mapping functions in anonymous namespace or adding static keyword solves the linking issue but then the compiler complains that the functions are defined but not used [-Wunused-function].
template<letter> static std::string const & mapping();
But, defining the specializations as constexpr, there is no longer any link or warning issue.
template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> constexpr std::string const & mapping<letter::P1>() { return space::s_##P2; }
I understand why the non-static version fails at link time and why the static version works and triggers warnings. But I don't understand why the constexpr specifier solves both issues.
Can you please give an explanation and even better, a rational in the standard ?
Function template specializations are functions, and are therefore subject to the one-definition rule in the same manner as functions that are not template specializations.
The linker errors you saw when the functions were declared neither static nor constexpr were due to multiple definitions of the same function template specializations which each had external linkage.
When you added static, you made the linkage internal. This made it safe for each translation unit to contain its own copy of the definitions. However, in any TU in which those functions were not called, the compiler knew that (due to internal linkage) they could not be called from any other TU either, making them unused.
With constexpr, the functions become inline implicitly according to the standard, but their linkage is not affected. Since they are inline, you can have multiple definitions, but since they have external linkage, the compiler does not complain when one TU does not use them.
functions declared with the constexpr specifier are inline functions.
From the C++ 20 Standard (9.2.5 The constexpr and consteval specifiers)
1 The constexpr specifier shall be applied only to the definition of a
variable or variable template or the declaration of a function or
function template. The consteval specifier shall be applied only to
the declaration of a function or function template. A function or
static data member declared with the constexpr or consteval specifier
is implicitly an inline function or variable (

Are constexpr functions implicitly static?

If I define a function in my program.cpp:
constexpr bool isThree(const int number)
{
return number == 3;
}
is that any different from declaring it static?
static constexpr bool isThree(const int number)
{
return number == 3;
}
It seems that those should be equivalent, since constexpr means the function is inline and therefore not shared among compilation units.
Are constexpr global functions implicitly static?
constexpr functions are implicitly inline.
inline is a linking feature. An inline function with definitions in different compilation units is not an error; if their definitions vary, your program is ill-formed no diagnostic required, but if they have the same definition then all but one version is discarded and that version is used.
static, on a non-method function, is also a linking feature. A static definition is not shared outside of its compilation unit; the compilation unit does not 'advertise' that it has a definition for isThree.
static on a method function has nothing to do with linking. In that case, it just means that this is not implicitly passed to the function. A method with/without this it doesn't work has differences, but they are mostly unrelated to them being constexpr. Note that in at least c++14 a constexpr method that doesn't use this can still be constant evaluated. Some versions of c++ make constexpr methods implicitly const; c++17 does not.
&isThree in one compilation unit and &isThree in another can (and usually do) vary when static (barring aggressive ICF, which is a matter for a different question). When inline they may not vary.
inline functions are shared between compilation units. Their full definition is also often visible in all compilation units aware of it, so it makes compiler "inlining" (as opposed to the keyword) your code easier. static are not. constexpr functions are implicitly inline, but not implicitly static.
Note that constexpr functions can be evaluated in a runtime context sometimes. When evaluated in a compile time context, their inline vs static or linkage state really doesn't matter.
constexpr means other things as well, but you wanted to know the difference between two different constexpr declarations, and none of those meanings change.
constexpr functions are not implicitly static. They have the same linkage as non-constexpr functions:
// external linkage
constexpr int f1(int x) { /* ... */ }
// internal linkage
static constexpr int f2(int x) { /* ... */ }
// internal linkage
namespace {
constexpr int f3(int x) { /* ... */ }
}
// no linkage
void enclosing() {
struct S {
constexpr int f4(int x) { /* ... */ }
};
}
When a constexpr function has external linkage, it has the same address in all translation units. When it has internal linkage, there is a different copy in each translation unit, and those copies have different addresses. However, I believe the result of calling a constexpr function should not depend on whether it has internal or external linkage (since constexpr functions may not contain static variables).

What means "obey ODR" in case of inline and constexpr function?

I just read that constexpr and inline functions obey one-definition rule, but they definition must be identical. So I try it:
inline void foo() {
return;
}
inline void foo() {
return;
}
int main() {
foo();
};
error: redefinition of 'void foo()',
and
constexpr int foo() {
return 1;
}
constexpr int foo() {
return 1;
}
int main() {
constexpr x = foo();
};
error: redefinition of 'constexpr int foo()'
So what exactly means that, constexpr and inline function can obey ODR?
I just read that constexpr and inline functions obey one-definition rule, but they definition must be identical.
This is in reference to inline functions in different translations units. In your example they are both in the same translation unit.
This is covered in the draft C++ standard 3.2 One definition rule [basic.def.odr] which says:
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), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) 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
and includes the following bullet:
each definition of D shall consist of the same sequence of tokens; and
You are defining functions repeatedly in one translation unit. This is always forbidden:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration
type, or template. (C++11 3.2/1)
For inline functions, you are allowed to define same function in exactly the same way in more than one translation unit (read: .cpp file). In fact, you must define it in every translation unit (which is usually done by defining it in a header file):
An inline function shall be defined in every translation unit in which it is odr-used. (C++11 3.2/3)
For "normal" (non-inline, non-constexpr, non-template, etc.) functions with external linkage (non-static) functions, this will usually (no diagnostic required) lead to a linker error.
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. (C++11 3.2/3)
To sum up:
Never define anything multiple times in one translation unit (which is a .cpp file and all directly or indirectly included headers).
You may put a certain number of things into header files, where they will be included once in several different translation units, for example:
inline functions
class types and templates
static data members of a class template.
If you have:
file1.cpp:
inline void foo() { std::cout << "Came to foo in file1.cpp" << std::endl; }
and
file2.cpp:
inline void foo() { std::cout << "Came to foo in file2.cpp" << std::endl; }
and you link those files together in an executable, you are violating the one-definition-rule since the two versions of the inline function are not same.

C++ call inline function from another cpp file

I'm trying to understand a few basics about extern, static, etc. and tried the following example, but I don't get why I can't call the function "just" because it's (possibly) inlined.
My first file : F1.cpp
#include <iostream>
void Modify();
int i;
int main() {
i = 1;
std::cout << "i = " << i << std::endl;
Modify();
std::cout << "i = " << i << std::endl;
return 0;
}
The second file : F2.cpp
#include <iostream>
extern int i;
inline void Modify() {
i = 99;
std::cout << "i = " << i << std::endl;
}
With inline keyword in F2.cpp, I get : undefined reference to Modify() in my F1.cpp file. Removing it, the code compiles and works fine.
I assume that the inline keyword in C++ has some sort of behaviour like the static keyword ?
I had a look at this topic aswell, but apart from the fact that the documentation says that an inline function should always be in the header file, I don't get it : C++ inline member function in .cpp file
Thanks for your help !
I assume that the inline keyword in C++ has some sort of behaviour like the static keyword ?
Similar, but different. The name still has external linkage, and the program behaves as if there's only one definition (for example, the function has the same address everywhere, and only one instance of any static variables). The effects of inline are:
The function can be defined in more than one translation unit, as long as all the definitions are identical. Regular functions can only be defined once.
The function must be defined in any translation unit that uses it. This allows the compiler to omit a non-inline definition if it doesn't need one.
Your code breaks the second rule, which might or might not lead to a link error. This is why inline functions usually need to be in headers, if you need to use them in more than one unit.
According to the C++ Standard (7.1.2 Function specifiers)
4....If a function with external linkage is declared inline in one
translation unit, it shall be declared inline in all translation units
in which it appears; no diagnostic is required.
and
4 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
In C ( section 6.7.4 Function specifiers of the C Standard ) function specifier inline for external functions has different semantic
7....An inline definition does not provide an external definition for the function, and does not forbid an external definition in another
translation unit. An inline definition provides an alternative to an
external definition, which a translator may use to implement any call
to the function in the same translation unit. It is unspecified
whether a call to the function uses the inline definition or the
external definition
Yes, inline has a meaning that's fairly similar to static. The specific requirement from the standard (§[basic.def.odr]/3) is:
An inline function shall be defined in every translation unit in which it is odr-used.
In this case, you've defined the inline function in one translation unit, but only declared it in the other, so you're not meeting the requirement above that it be defined in the TU where it's used.
An inline function can still have external linkage. When you do this, the standard guarantees that it results in a single function that will have the same address throughout the program.
Just in case it wasn't clear: a translation unit is basically a source file, after preprocessing, so it includes everything directly in that source file plus everything in the headers it includes, minus anything skipped over due to things like #ifdef, #if, etc.
When you declare a function inline, only the translation unit that it is defined in (in this case, F2.cpp) has access to this function. If you instead put it in a header file (say F.h), and #include "F.h" in both F1.cpp and F2.cpp, then the inline function is defined twice, once in each translation unit. Normally, this would cause a linker error, but since you declared the function inline, the linker doesn't know about your Modify() function.

inline function and class and header file

Will any function defined in the header file automatically be inline?
If I declare a function in a class and give the definition outside using keyword inline, will this function be inline? If it is, why this does not against the law that inline function should be given the body at declaration?
Any function defined inside a class definition is inline. Any function marked inline is also inline.
class C {
int f() { return 3; } // inline
int g();
int h();
}
inline int C::g() { return 4; } // inline
int C::h() { return 5; } // not inline
If all this code is in a header and that header is used in more than one translation unit you'll get a complaint that C::h has more than one definition. C::f and C::g are okay because they're inline. That's the primary role of inline these days: to permit defining the same function in multiple places (provided the definitions are "the same").
is it that any function defined in the header file will automatically be inline?
No, you should make any function defined outside of class body inline by hands. Otherwise, most likely you would get ODR violation (if include header in several translation units).
ISO C++11
3.2 One definition rule
1: No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
[...]
4: Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is odr-used.
if I declare a function in a class and give the definition outside using keyword inline, will this function be inline? If it is, why this does not against the law that inline function should be given the body at declaration?
There are several ways to do member function inline:
First, according to 7.1.2/3:
A function defined within a class definition is an inline function. The inline specifier shall not appear on a block scope function declaration.90 If the inline specifier is used in a friend declaration, that declaration shall be a definition or the function shall have previously been declared inline.
struct First
{
void first(){}
};
Second, Third and Fourth, according to 9.3/3:
An inline member function (whether static or non-static) may also be defined outside of its class definition provided either its declaration in the class definition or its definition outside of the class definition declares the function as inline. [ Note: Member functions of a class in namespace scope have external linkage. Member functions of a local class (9.8) have no linkage. See 3.5. —end note ]
struct STF
{
void second();
inline void third();
inline void fourth();
};
inline void STF::second(){}
void STF::third(){}
inline void STF::fourth(){}
inline is a "hint", insofar as the compiler doesn't have to honor it. It can make things inline that you don't mark inline and doesn't have to inline things that you mark as inline.
By that, I mean you shouldn't rely on it. Many recommend that you don't even use it as it is misleading. Most modern compilers completely ignore it.
The only practical use is to allow you to put static implementations into a header. Whether or not that is a good thing to do is arguable.