Этот вопрос возник в контексте этого ответа.
Как и следовало ожидать, эта единица перевода не компилируется:
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; }
Пользователь Oliv услужливо указал мне на этот соответствующий абзац в стандарте, но я все еще немного сбит с толку, поэтому я надеялся, что кто-нибудь сможет объяснить более простыми словами логику, стоящую за этим (например, что должно или не следует рассматривать как нарушение 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 был применен именно для того, чтобы избежать подобных проблем.