Добрый вечер,
появилась проблема: есть два класса, хранящие константные массивы константного размера (которые приходят из кодогенератора). Делают с ними почти одно и тоже, сейчас делается копипейст кода, нехорошо.
Классический случай -- делаем предка и функции на него перелагаем. Но приходится вручную передавать размеры массива и vtable появляется (чтобы засады себе не делать).
Используем вместо обычного предка template c "non-type template parameter", размером массива, и aggreation вместо derivation. Копипейста нету, но появляется template bloat (то есть bloat уже был, но стал неявным).
Можно добавить ещё один вспомогательный класс и добить врага, но как-то влом. А почему бы не решить так: оставить template + aggregation, но сделать особую специализацию "implementation class".
То есть так:
template<size_t SIZE>
class C
{
const int (&m_array) [SIZE][SIZE];
static const size_t s_implementationSize = ~0u;
static const bool s_isImplementation = (SIZE == s_implementationSize);
typedef C<s_implementationSize> Implementation;
template<size_t OTHER_SIZE>
friend class C;
static void Do(_In_count_x_(size * size) const int* const array, const size_t size)
{
static_assert(s_isImplementation, "implementation-instantiated only");
}
C operator=(C);
C(C&);
C();
public:
explicit C (const int (&array)[SIZE][SIZE]) :
m_array(array) {}
void Do() const
{
static_assert(!s_isImplementation, "must not be implementation-instantiated");
Implementation::Do(&(m_array[0][0]), SIZE);
}
};
Всё есть, что надо, и в одном месте. Но такая народная самодеятельность немного стрёмна, очень желаю сослаться на какого-нибудь классика. В интернете все встреченные версии используют наследование. Не подскажите, кто уже писАл такое?
Кстати, можно ограничить friend-statement, чтобы "C<FOO> {friend} C<~0u>", но "C<FOO> {!friend} C<BAR>", где BAR != ~0u ?