Home > front end >  ODR violation if template is defined in multiple translation units for different types?
ODR violation if template is defined in multiple translation units for different types?

Time:08-26

I recently got to know that the following code is ill-formed, NDR:

// foo.h
template <typename T>
void foo();

// foo_bar.cpp
template <>
void foo<bar>()
{ /* Implementation for bar */ }

// foo_baz.cpp
template <>
void foo<baz>()
{ /* Implementation for baz */ }

Due to the specializations not being declared in foo.h. The reason for not declaring them in foo.h is to avoid #include'ing the definitions of baz and bar (long build times).

Explicit instantiations do not suffer from this problem - there's no need to declare them in the header. Therefore I thought about solving the above problem using explicit instantiation instead:

// foo.h
template <typename T>
void foo();

// foo_bar.cpp
template <typename T>
void foo()
{ /* Implementation for bar */ }

template void foo<bar>();

// foo_baz.cpp
template <typename T>
void foo()
{ /* Implementation for baz */ }

template void foo<baz>();

In some way, it would be replacing specializations with explicit instantiations. But then comes my question: is having two different implementations of the primary template foo<T> violating ODR, assuming they are instantiated for different types?

CodePudding user response:

Yes, this would technically still an ODR violation (presuming that the template definitions are not identical in both translation units).

You'll probably get away with this, with most C compilers, but this is still a technical ODR violation -- the same template has a different definition in different translation units.

If, on the other hand, you turn it into two template specializations (and not even define the template itself), then it would not be an ODR violation. This is what specialized templates are for.

CodePudding user response:

Based on the feedback from the comments, the answer is yes, this is an ODR violation.

To solve the original problem, a better solution is to declare the template specializations in the header. To avoid including the dependencies bar and baz, it's enough to forward-declare them.

  • Related