Подскажите название велосипеду (anti-template-bloat)
От: superlexx  
Дата: 02.11.09 21:49
Оценка:
Добрый вечер,

появилась проблема: есть два класса, хранящие константные массивы константного размера (которые приходят из кодогенератора). Делают с ними почти одно и тоже, сейчас делается копипейст кода, нехорошо.
Классический случай -- делаем предка и функции на него перелагаем. Но приходится вручную передавать размеры массива и 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 ?
template bloat non-template parameter
Re: Подскажите название велосипеду (anti-template-bloat)
От: Кодт Россия  
Дата: 03.11.09 01:10
Оценка:
Здравствуйте, superlexx, Вы писали:

S>Добрый вечер,


S>появилась проблема: есть два класса, хранящие константные массивы константного размера (которые приходят из кодогенератора). Делают с ними почти одно и тоже, сейчас делается копипейст кода, нехорошо.


Вот бы ты ещё показал, что за классы приходят из кодогенератора...
А то как-то не уловил идею. Где там одинаковый код (копипастящийся), где специфичный...

Что же касается массивов — чтобы не изобретать лишних велосипедов, посмотри на boost::array.
Перекуём баги на фичи!
Re[2]: Подскажите название велосипеду (anti-template-bloat)
От: superlexx  
Дата: 03.11.09 07:30
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Вот бы ты ещё показал, что за классы приходят из кодогенератора...

К>А то как-то не уловил идею. Где там одинаковый код (копипастящийся), где специфичный...
Приходят два 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)
От: Кодт Россия  
Дата: 04.11.09 12:47
Оценка: 8 (1)
Здравствуйте, superlexx, Вы писали:

S>Приходят два 2-dim C array, которые становятся static const member соответственно двух классов. Эти классы проверяют массивы на вшивость и читают элементы (типа enum) немного хитрым способом (с преобразованием индексов). Код проверки и чтения использует размеры массива в
for (size_t i = 0; i < _countof(s_array); i++)
. Это вместе с преобразованием индексов копипастится.

S>Работает этот код на устройстве, питающимся от аккумулятора, кроме нашей ещё много подсистем. ROM желательно как можно меньше использовать, код не раздувать.
S>Кодогенератор я могу подгибать под себя.

Если не хочешь раздувать код, то параметризуй механику не во время компиляции, а во время исполнения.
// было
template<size_t NX, size_t NY>
struct the_array
{
    static const C data[NX][NY];
    
    ......
    // преобразование координат хитрым способом
    // std::pair чисто для иллюстрации, можешь по-своему сделать, как удобно
    pair<size_t,size_t> translate(size_t x, size_t y) const { size_t x1 = (.....), y1 = (.....); return make_pair(x1,y1); }
    // доступ к элементу
    C const& at(size_t x, size_t y) const { pair<size_t,size_t> xy = translate(x,y); return data[xy.first][xy.second]; }
    ......
};

the_array<5,7> arr = { {1,2,3,4,5,6,7}, {8,9,10,11,12,13,14}, ..... };
the_array<2,3> brr = { {1,2,3}, {4,5,6} };


// стало
struct array_helper
{
    size_t NX, NY;
    static const C* data; // линейный массив
    
    array_helper(size_t NX, size_t NY, const C* data) : NX(NX), NY(NY), data(data) {}
    
    .....
    // преобразование всё то же
    pair<size_t,size_t> translate(size_t x, size_t y) const { ..... }
    // добавляется получение линейного индекса
    size_t linearize(pair<size_t,size_t> xy) const { return xy.first * NY + xy.second; }
    // доступ очевиден:
    C const& at(size_t x, size_t y) const { return data[linearize(translate(x,y))]; }
    .....
};

C const arr_data[5*7] = { 1,2,3,4,5,6,7, 8,9,10,11,12,13,14, ..... };
array_helper const arr(5,7,arr_data);

C const brr_data[2*3] = { 1,2,3, 4,5,6 };
array_helper const brr(2,3,brr_data);

То есть, экономим на дублировании кода, но затрачиваемся на хранение констант. Плюс код будет несколько более тяжёлый, потому что константы не прямо в коде прошиты, а вычитываются из памяти.

К>>Что же касается массивов — чтобы не изобретать лишних велосипедов, посмотри на boost::array.

S>От STL пришлось отказаться (я был за STL), boost тоже не используется. Выходит опять велосипед.
... или копипаст. boost::array прост как сибирский валенок.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[4]: Подскажите название велосипеду (anti-template-bloat)
От: denisko http://sdeniskos.blogspot.com/
Дата: 04.11.09 19:46
Оценка:
Здравствуйте, Кодт, Вы писали:
К>... или копипаст. boost::array прост как сибирский валенок.
Ви таки не видели сибирских валенков, чтоб вы были здорово. Они самая что нинаесть непростая вещь на свете.
<Подпись удалена модератором>
Re: Подскажите название велосипеду (anti-template-bloat)
От: remark Россия http://www.1024cores.net/
Дата: 09.11.09 22:29
Оценка:
Здравствуйте, superlexx, Вы писали:

S>Кстати, можно ограничить friend-statement, чтобы "C<FOO> {friend} C<~0u>", но "C<FOO> {!friend} C<BAR>", где BAR != ~0u ?


friend class C<FOO>;



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Подскажите название велосипеду (anti-template-bloat)
От: superlexx  
Дата: 10.11.09 16:24
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Если не хочешь раздувать код, то параметризуй механику не во время компиляции, а во время исполнения.

Спасибо, примерно так и сделал. Только ctor сделал template, чтобы выводить размер массива.

S>>От STL пришлось отказаться (я был за STL), boost тоже не используется. Выходит опять велосипед.

К>... или копипаст. boost::array прост как сибирский валенок.
За несанкционированный копипаст чужого кода по рукам бьют (и правильно). Велосипедный std::array у меня уже есть (с дополнениями), но опять же не хочется его интегрировать.
Re[2]: Подскажите название велосипеду (anti-template-bloat)
От: superlexx  
Дата: 10.11.09 16:54
Оценка:
Здравствуйте, 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. Кажется, что вариантов больше нет.

Но это так, ради интереса, так как уже не нужно.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.