In the C++20 draft (N4868) there are two relevant rules about definition reachability:
- Inline functions must have their definition reachable in every translation unit in which they are ODR-used:
[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.
- Function templates must have their definition reachable in every translation unit in which they are implicitly instantiated, unless there is an explicit instantiation somewhere:
[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:
- Does [basic.def.odr/11] apply to function templates, or only to ordinary functions?
- In other words, is a function template “a function” in the sense of [basic.def.odr/11], or do the special rules in [temp.pre/10] override it?
inlinefrom the declaration, so perhaps the inline-rule doesn't apply here?