This question arised in the context of this answer.
As I would expect, this translation unit does not compile:
template int getNum()
Both, explicit specialization and explicit instantiation definition will violate ODR based on the context they are used and the meaning of the entities they generate.
The following explain the first and the third case and why they does violate ODR with NDR [temp.spec]/5
For a given template and a given set of template-arguments,
(5.1) an explicit instantiation definition shall appear at most once in a program,
(5.2) an explicit specialization shall be defined at most once in a program (according to 6.2), [...]
function templates may have different points of instantiation in both the same translation unit where they are defined and in others translation units, these specialization are guaranteed not to violate ODR when the meaning of these specialization is the same in all the points of instantiation.
since by [temp.point]/6
An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.
and [temp.point]/8
[...] If two different points of instantiation give a template specialization different meanings according to the one-definition rule (6.2), the program is ill-formed, no diagnostic required.
the second case does not violate ODR, because the meaning of the instantiations in these TU is the same.
// decl.h
template <int Num> int getNum() { return Num; }
// a.cc
#include <decl.h>
template int getNum<0>();
// b.cc
#include <decl.h>
template int getNum<0>();
int main() { getNum<0>(); return 0; }
But the last is certainly not a valid one (violate ODR NDR), because even the function templates have the same signatures the instantiations from them will have different meanings. You can't relay in the result you got, the standard don't guarantee the behavior when these violation happens.
// a.cc
template <int Num> int getNum() { return Num + 1; }
template int getNum<0>();
// b.cc
#include <iostream>
template <int Num> int getNum() { return Num; }
template int getNum<0>();
int main() { std::cout << getNum<0>() << std::endl; return 0; }
Eureka! I finally fall on the relevant paragraph, [temp.spec]/5
For a given template and a given set of template-arguments,
(5.1) an explicit instantiation definition shall appear at most once in a program,
(5.2) an explicit specialization shall be defined at most once in a program, as specified in [basic.def.odr], and
- (5.3) both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit instantiation follows a declaration of the explicit specialization.
An implementation is not required to diagnose a violation of this rule.
So explicit template instantiation definition (not implicit instantiation) can cause ODR violation, no diagnostic required (and at least gcc and clang - ld toolchains do not produce diagnostic)