Вот одна идея, которая, я не уверен, насколько она применима для вас:
#include <cstddef>
struct A {}; struct B {}; struct C {};
template <size_t Id> constexpr size_t getId() { return Id; }
template <typename T> struct traits {};
template size_t getId<0>();
template <> struct traits<A> { static constexpr size_t id() { return getId<0>(); }};
template size_t getId<1>();
template <> struct traits<B> { static constexpr size_t id() { return getId<1>(); }};
/* This fails to compile
template size_t getId<1>();
template <> struct traits<C> { static constexpr size_t id() { return getId<1>(); }};
*/
int main() { return 0; }
Это основано на использовании явного создания экземпляра функции для шаблона.Подводный камень, очевидно, заключается в том, что вы можете забыть добавить этот экземпляр и по-прежнему использовать функцию, и тогда она не будет скомпилирована.Вы можете определить некоторый макрос препроцессора, чтобы гарантировать, что с ним всегда определяются черты.
РЕДАКТИРОВАТЬ: Как указано Oliv , вышеупомянутое решение работает, только когда все экземпляры шаблона происходят втот же переводчик.Эта версия работает с единицами компиляции, хотя она более подвержена ошибкам (параметры шаблона и возвращаемые значения должны совпадать).
#include <cstddef>
struct A {}; struct B {}; struct C {};
template <size_t Id> constexpr size_t getId();
template <typename T> struct traits {};
template <> constexpr size_t getId<0>() { return 0; }
template <> struct traits<A> { static constexpr size_t id() { return getId<0>(); }};
template <> constexpr size_t getId<1>() { return 1; }
template <> struct traits<B> { static constexpr size_t id() { return getId<1>(); }};
/* This fails to compile
template <> constexpr size_t getId<1>() { return 1; }
template <> struct traits<C> { static constexpr size_t id() { return getId<1>(); }};
*/
int main() { return 0; }
РЕДАКТИРОВАТЬ 2: Я опубликовал вопрос Почему явный шаблонинстанцирование не нарушило ODR? из-за поведения, которое я обнаружил удивительным при написании этого ответа.См. Там больше подробностей о том, что может или не может не скомпилироваться.