5

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?
4
  • You can remove the inline from the declaration, so perhaps the inline-rule doesn't apply here? Commented Aug 30 at 13:21
  • yeah, I mean there is probably no good reason to write code like that (I don't know if there is any practical effect in declaring template as inline). The question is just for a sake of language lawyering Commented Aug 30 at 13:37
  • 3
    "This program compiles and runs" - Which means nothing! Commented Aug 30 at 14:01
  • A compiling program is not necessarily a correct program (specially true under UB conditions). Commented Aug 30 at 15:32

1 Answer 1

10

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.