появилась проблема: есть два класса, хранящие константные массивы константного размера (которые приходят из кодогенератора). Делают с ними почти одно и тоже, сейчас делается копипейст кода, нехорошо.
Классический случай -- делаем предка и функции на него перелагаем. Но приходится вручную передавать размеры массива и 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 ?
Здравствуйте, superlexx, Вы писали:
S>Добрый вечер,
S>появилась проблема: есть два класса, хранящие константные массивы константного размера (которые приходят из кодогенератора). Делают с ними почти одно и тоже, сейчас делается копипейст кода, нехорошо.
Вот бы ты ещё показал, что за классы приходят из кодогенератора...
А то как-то не уловил идею. Где там одинаковый код (копипастящийся), где специфичный...
Что же касается массивов — чтобы не изобретать лишних велосипедов, посмотри на boost::array.
Перекуём баги на фичи!
Re[2]: Подскажите название велосипеду (anti-template-bloat)
Здравствуйте, Кодт, Вы писали:
К>Вот бы ты ещё показал, что за классы приходят из кодогенератора... К>А то как-то не уловил идею. Где там одинаковый код (копипастящийся), где специфичный...
Приходят два 2-dim C array, которые становятся static const member соответственно двух классов. Эти классы проверяют массивы на вшивость и читают элементы (типа enum) немного хитрым способом (с преобразованием индексов). Код проверки и чтения использует размеры массива в
for (size_t i = 0; i < _countof(s_array); i++)
. Это вместе с преобразованием индексов копипастится.
Работает этот код на устройстве, питающимся от аккумулятора, кроме нашей ещё много подсистем. ROM желательно как можно меньше использовать, код не раздувать.
Кодогенератор я могу подгибать под себя.
К>Что же касается массивов — чтобы не изобретать лишних велосипедов, посмотри на boost::array.
От STL пришлось отказаться (я был за STL), boost тоже не используется. Выходит опять велосипед.
Re[3]: Подскажите название велосипеду (anti-template-bloat)
Здравствуйте, superlexx, Вы писали:
S>Приходят два 2-dim C array, которые становятся static const member соответственно двух классов. Эти классы проверяют массивы на вшивость и читают элементы (типа enum) немного хитрым способом (с преобразованием индексов). Код проверки и чтения использует размеры массива в
for (size_t i = 0; i < _countof(s_array); i++)
. Это вместе с преобразованием индексов копипастится. S>Работает этот код на устройстве, питающимся от аккумулятора, кроме нашей ещё много подсистем. ROM желательно как можно меньше использовать, код не раздувать. S>Кодогенератор я могу подгибать под себя.
Если не хочешь раздувать код, то параметризуй механику не во время компиляции, а во время исполнения.
То есть, экономим на дублировании кода, но затрачиваемся на хранение констант. Плюс код будет несколько более тяжёлый, потому что константы не прямо в коде прошиты, а вычитываются из памяти.
К>>Что же касается массивов — чтобы не изобретать лишних велосипедов, посмотри на boost::array. S>От STL пришлось отказаться (я был за STL), boost тоже не используется. Выходит опять велосипед.
... или копипаст. boost::array прост как сибирский валенок.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[4]: Подскажите название велосипеду (anti-template-bloat)
Здравствуйте, Кодт, Вы писали: К>... или копипаст. boost::array прост как сибирский валенок.
Ви таки не видели сибирских валенков, чтоб вы были здорово. Они самая что нинаесть непростая вещь на свете.
<Подпись удалена модератором>
Re: Подскажите название велосипеду (anti-template-bloat)
Здравствуйте, superlexx, Вы писали:
S>Кстати, можно ограничить friend-statement, чтобы "C<FOO> {friend} C<~0u>", но "C<FOO> {!friend} C<BAR>", где BAR != ~0u ?
Здравствуйте, Кодт, Вы писали:
К>Если не хочешь раздувать код, то параметризуй механику не во время компиляции, а во время исполнения.
Спасибо, примерно так и сделал. Только ctor сделал template, чтобы выводить размер массива.
S>>От STL пришлось отказаться (я был за STL), boost тоже не используется. Выходит опять велосипед. К>... или копипаст. boost::array прост как сибирский валенок.
За несанкционированный копипаст чужого кода по рукам бьют (и правильно). Велосипедный std::array у меня уже есть (с дополнениями), но опять же не хочется его интегрировать.
Re[2]: Подскажите название велосипеду (anti-template-bloat)
Здравствуйте, remark, Вы писали:
R>Здравствуйте, superlexx, Вы писали:
S>>Кстати, можно ограничить friend-statement, чтобы "C<FOO> {friend} C<~0u>", но "C<FOO> {!friend} C<BAR>", где BAR != ~0u ?
R>
R>friend class C<FOO>;
R>
Не совсем то, что надо. Хотелось так: С<N> → C<~0u> ∀N, но C<M> ↛ C<N> ∀ (N != ~0u).
template <size_t N> friend class C;
даёт первое, но также C<M> → C<N> ∀ (N,M != ~0u), это я хотел предотвратить.
friend class C<~0u>;
даёт С<~0u> → C<N> ∀N. Кажется, что вариантов больше нет.