Этот вопрос возник в контексте этого ответа .
Как и следовало ожидать, этот блок перевода не компилируется:
template <int Num> int getNum() { return Num; }
template int getNum<0>();
template int getNum<0>(); // error: duplicate explicit instantiation of 'getNum<0>'
int main() { getNum<0>(); return 0; }
Я понимаю это,Я пытался сделать один и тот же явный экземпляр шаблона дважды.Однако оказывается, что, разделяя это на разные единицы, он компилирует:
// 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; }
Я этого не ожидал.Я предположил, что несколько явных экземпляров шаблона с одинаковыми параметрами могут нарушить ODR, но, похоже, это не так.Это, однако, не помогает:
// decl.h
template <int Num> int getNum();
// a.cc
#include "decl.h"
template <> int getNum<0>() { return 0; }
// b.cc
#include "decl.h"
template <> int getNum<0>() { return 0; }
int main() { getNum<0>(); return 0; }
Пользователь Олив услужливо указал мне на этот соответствующий параграф в стандарте , но я все еще несколько смущен этим,поэтому я надеялся, что кто-то сможет объяснить в более простых терминах логику, лежащую в основе этого (например, что следует или не следует рассматривать как нарушение ODR и почему мои ожидания были неверными).
РЕДАКТИРОВАТЬ:
В качестве еще одного примера, вот программа, разделенная на две единицы, которая корректно компилируется, но при этом дает удивительно неожиданные результаты:
// 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; }
Вывод:
1
В этом случае удаление явногоШаблон экземпляров выдает 0
.Я знаю, что наличие двух шаблонов с разными определениями не является распространенным случаем, но я думал, что ODR был строго применен, чтобы избежать такого рода проблем.