Вы можете объявить следующий шаблон класса удобства, Foo_number_taker
:
template<typename> struct Foo_number_taker;
Затем, с помощью следующего макроса, DEF_FOO_NUMBER_TAKER
:
#define DEF_FOO_NUMBER_TAKER(N) template<> \
struct Foo_number_taker<Foo##N> { \
static constexpr unsigned value = N; \
};
Вы можете легко специализировать шаблон класса Foo_number_taker
выше для Foo1
, Foo4
, Foo8
и Foo16
:
DEF_FOO_NUMBER_TAKER(1)
DEF_FOO_NUMBER_TAKER(4)
DEF_FOO_NUMBER_TAKER(8)
DEF_FOO_NUMBER_TAKER(16)
Например, DEF_FOO_NUMBER_TAKER(8)
будет расширяться до:
template<> struct Foo_number_taker<Foo8> { static constexpr unsigned value = 8; };
Следовательно, он каким-то образом ассоциирует тип Foo8
с числом 8 , а макрос предотвращает ошибочные ассоциации (например, ассоциирование Foo8
с числом 4 ) от происходящего. Аналогично для остальных специализаций.
При желании вы можете просто определить следующий шаблон переменной:
template<typename FooN>
static auto constexpr Foo_number_v = Foo_number_taker<FooN>::value;
Наконец, вы определяете свой шаблон функции bar()
, чтобы воспользоваться преимуществами этого шаблона переменной выше, чтобы выяснить номер, связанный с параметром шаблона FooN
:
template<typename FooN>
void bar(FooN* foo) {
auto constexpr N = Foo_number_v<FooN>;
for(unsigned i = 0; i < N; ++i) {
// ...
}
}
Использовать его просто:
auto main() -> int {
Foo1 *f1;
Foo4 *f4;
// ...
bar(f1);
bar(f4);
}