Вы можете использовать для этого подход X macro :
valid_sizes.hpp
// Note: no include guards!!
PROCESS_SIZE(1)
PROCESS_SIZE(2)
PROCESS_SIZE(7)
PROCESS_SIZE(9)
#undef PROCESS_SIZE
foo.cpp
// ...
#define PROCESS_SIZE(n) template struct Foo<n>;
#include "valid_sizes.hpp"
bar.cpp
// ...
#define PROCESS_SIZE(n) some_other_use_of<n>;
#include "valid_sizes.hpp"
В качестве альтернативы, вместо списка вручную, вы можете использовать Boost.Preprocessor:
process_sizes.hpp
#pragma once
#define PROCESS_SIZES(macro, data) BOOST_PP_SEQ_FOR_EACH(macro, data, (1)(2)(7)(9))
некоторый заголовочный файл
#define INSTANTIATE_CLASS(r, Name, size) template class Name<size>;
foo.cpp
#include "process_sizes.hpp"
// ...
PROCESS_SIZES(INSTANTIATE_CLASS, Foo)
bar.cpp
#include "process_sizes.hpp"
// ...
PROCESS_SIZES(INSTANTIATE_CLASS, Bar)
#define OTHER_SIZE_BASED_WORK(r, data, size) other_use_of<size>;
PROCESS_SIZES(OTHER_SIZE_BASED_WORK, whatever)
Обратите внимание, что явные определения экземпляров должны встречаться в области имен, поэтому невозможно поместить их в функцию, подобную вашей попытке instantiator
.
А также обратите внимание, что неявное создание экземпляров (например, вызванное ссылкой на класс в контексте, который требует его определения) не является "видимым" вне единицы перевода, поэтому его нельзя использовать в качестве замены для явная реализация.
Другими словами, для того, чтобы один и тот же список размеров делал разные вещи, требуется дублирование списка для каждого использования, использование макросов или использование пользовательской генерации кода вне конвейера компиляции C ++. Я считаю макросы самыми простыми и удобными в обслуживании.