c++templateslanguage-lawyerinlineone-definition-rule

Is an "inline function template" considered a "inline function" with respect to ODR rules?


In the C++20 draft (N4868) there are two relevant rules about definition reachability:

[basic.def.odr/11] A definition of an inline function or variable shall be reachable from the end of every definition domain in which it is odr-used outside of a discarded statement.

[temp.pre/10] A definition of a function template … shall be reachable from the end of every definition domain in which it is implicitly instantiated … unless the corresponding specialization is explicitly instantiated … in some translation unit; no diagnostic is required.


Now consider the following program split into two files:

// file1.cpp
template<class T>
inline void foo(T a); // declaration

int main() {
    foo(123); // implicit instantiation of foo<int>
}
// file2.cpp
#include <iostream>

template<class T>
inline void foo(T a) {
    std::cout << a;
}

template void foo<int>(int); // explicit instantiation definition

This program compiles and runs under MSVC, printing 123.

By [temp.pre/10], this seems OK: foo<int> is implicitly instantiated in file1.cpp, but there is an explicit instantiation in file2.cpp, so the definition doesn’t need to be reachable in file1.cpp.

But [basic.def.odr/11] says that an inline function definition must be reachable in every TU where it is ODR-used. In file1.cpp, foo<int> is called (ODR-used), but there is no reachable definition of the inline function template there.


Question

Is this program UB or not? More specifically:


Solution

  • A function template is not a function. It can be instantiated into a specialisation, and that specialisation is a function. (e.g., foo names a function template, and foo<int> would name a specialisation of that function template and is a function)

    Both of the statements apply at once. They both say 'if these conditions are not met the program is ill-formed', not that 'if these conditions are met the program is not ill-formed'.

    So, [temp.pre]/10 would not make this program ill-formed, because there is a corresponding explicit instantiation. But [basic.def.odr]/11 makes this program ill-formed anyways because foo<int> is an inline function.