Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Шаблонная магия. Возможно ли реализовать?


Автор: kuzulis 9.1.2014, 11:35
Всем доброго времени.

Имеется некое ембеддед у-во (на ARM MCU). Оно имеет адресное пространство из 4 байтных регистров, где каждый регистр, соответственно, имеет уникальный адрес и назначение.

Для простоты пусть будет как-то так:

Цитата


Registry    Base address
~~~~~    ~~~~~~~~~

Reg_x       0x0000 -|
Reg_y       0x0004  | = > Сущность №1 (Entity A)
Reg_z       0x0008 -|

Reg_x       0x001C -|
Reg_y       0x0010  | = > Сущность №2 (Entity B)
Reg_z       0x0014 -|



Т.е. у нас есть как-бы две разных сущности  (Entity A, B) , каждая из которых состоит из трех однотипных регистров x,y,z. 

Также, каждая сущность имеет разный набор флагов (масок) для своих регистров):

Код

typedef enum {
    flag1 = 0x00000001,
    flag2 = 0x00000002
} entity_a_reg_flags_t

typedef enum {
    flag1 = 0x00000040,
    flag2 = 0x00000080
} entity_b_reg_flags_t


Далее, объявлена некая структура, описывающая карту регистров сущностей:
Код


typedef struct {
    uint32_t reg_X;
    uint32_t reg_Y;
    uint32_t reg_Z;
} entity_t


На C имеется API для доступа к регистрам и установки/сброса флагов:
Код


#define ENTITY_A      (volatile entity_t*)(0x0000) // базовый адрес сущности А
#define ENTITY_B      (volatile entity_t*)(0x001C) // базовый адрес сущности B

void entityA_setFlagForRegX(entity_a_reg_flags_t flags, bool enable)
{
    if (enable)
        ENTITY_A->reg_X |= flags;
    else
        ENTITY_A->reg_X &= ~flags;
}

void entityA_setFlagForRegY(entity_a_reg_flags_t flags, bool enable);
void entityA_setFlagForRegZ(entity_a_reg_flags_t flags, bool enable)

void entityB_setFlagForRegX(entity_a_reg_flags_t flags, bool enable)
void entityB_setFlagForRegY(entity_a_reg_flags_t flags, bool enable)
void entityB_setFlagForRegZ(entity_a_reg_flags_t flags, bool enable)


ИМХО, это API ужасно. smile

Так, на С++ (без шаблонов) я бы реализовал это как-то так (псевдо код):
Код

class Entity
{
public:
    Entity(uint32 baseAddr)
    {
        m = reinterpret_cast<struct map *>(baseAddr);
    }
    virtual void setRegX(bool enable)  = 0;
    virtual void setRegY(bool enable)  = 0;
    virtual void setRegZ(bool enable)  = 0;

protected:
    struct map {
        uint32_t regx;
        uint32_t regy;
        uint32_t regz;
    };
    map *m;
}

class EntityA : public Entity
{
public:
    enum Flags {
        flag1 = 0x00000001,
        flag2 = 0x00000002
    };
    EntityA(Flags flags) : Entity(0x0000), flags(flags) {}

    virtual void setRegX(bool enable) 
    {
        if (enable)
            m->regX |= flags;
        else 
            m->regX &= ~flags;
    }
    virtual void setRegY(bool enable)
    { ... }

    virtual void setRegZ(bool enable)
    { ... }

private:
    Flags flags;
}

class EntityB : public Entity
{
public:
    enum Flags {
        flag1 = 0x00000040,
        flag2 = 0x00000080
    };

    ...
    ...
}

// Использование:

int main()
{
    EntityA ea(EntityA::flag2);
    ea.setRegY(true);
}



Но опять-таки это накладно, громоздко и пр.. Хотелось бы упростить это с использованием шаблонов..

Например, как-то так:

Код

int main()
{
    Periphery<EntityA> ea(EntityA::flag2);
    ea.setRegY(true);
}


возможно ли это? Или можно как-нибудь по другому упростить API?  smile 






Автор: baldina 9.1.2014, 13:14
если переменная часть - базовый адрес и набор флагов, можно типа такого (проверки не стал делать что бы не загромождать)

Код

class Entity
{
public:
   Entity (uint32_t baseAddr) : e (reinterpret_cast<uint32_t*>(baseAddr)) {}

   template <size_t N>
   void set  (uint32_t flags)   { enable (e+N, flags); }

   template <size_t N>
   void reset (uint32_t flags)  { disable (e+N, flags); }
private:
   static void enable  (uint32_t *addr, uint32_t flags) { *addr |= flags;  }
   static void disable (uint32_t *addr, uint32_t flags) { *addr &= ~flags; }
   uint32_t *e;
};

class EntityA : public Entity {
    public:
      EntityA () : Entity (0x0000) {}
    enum {
     flag1 = 0x00000001,
     flag2 = 0x00000002,
     flag3 = 0x00000004
    };      
};

class EntityB : public Entity {
    public:
      EntityB () : Entity (0x001C) {}
    enum {
     flag1 = 0x00000040,
     flag2 = 0x00000080,
     flag3 = 0x000000C0
    };
};

// using:
EntityA a;
a.set<1> (EntityA::flag1 | EntityA::flag2);
a.reset<2> (EntityA::flag3);

это наверно не идеальный вариант, зависит от того, как вы будете использовать, но в качестве источника некоторых идей думаю пойдет

Автор: kuzulis 9.1.2014, 17:21
Да, спасибо.. Но все-равно что-то не то.. Наверное останусь на чистых С-ях и попробую переделать API на что-то человеческое.. 

Автор: baldina 9.1.2014, 17:55
тогда достаточно одной функции
Код

void set (uint32_t base, unsigned reg, uint32_t flags, bool enable)  { 
   uint32_t *addr = reinterpret_cast<uint32_t*>(base) + reg;
   if (enable)
     *addr |= flags;  
   else
     *addr &= ~flags; 
}

ну и вариации по желанию
Код

set_A_X (uint32_t flags, bool enable) {
   set (A_base, 0, uint32_t flags, bool enable);
}


Автор: baldina 9.1.2014, 18:13
вариации можно темплейтами (мне правда не нравится)))
Код

enum EntityAddr { EntityA=0x123456, EntityB=0x123457 };

template <EntityAddr Base, char Reg, bool Enable>
void set_reg (int flags)  { 
   uint32_t *addr = reinterpret_cast<uint32_t*>(Base) + (Reg-'X');
   if (Enable)
     *addr |= flags;  
   else
     *addr &= ~flags; 
}
....
set_reg <EntityA, 'X', true>(flags1|flags2);

Автор: akizelokro 9.1.2014, 20:35
Недавно я наблюдал споры о некоем сингелтоне, точнее, о его потоконебезопасности на компиляторах, не поддерживающих стандарт С++ 11 чтоли. Но не суть важно. Но это я всё посчитал лабудой, так как там стоит дождаться выхода компилятора, соответствующего стандарту. А вот что мне показалось более забавным. Раз возможно описать Singleton, то можно описать и Doubleton (класс, который будет содержать только два экземпляра), и Tripleton (три, соответственно), .. и N-ton.
От нефикх делать я даже несколько вариантов таких закорючек составил. Так что не парьтесь.
Реализуйте шаблон для Entity, а дальше Entity объединяйте с Nton'ом (вот вам и своеобразный аналог enum через шаблоны).  smile

Добавлено @ 20:37
Doubleton, Tripleton и Nton - теперь мой копирайт. При перепечатке "ля-ля-тополя" и так далее smile 

Автор: baldina 9.1.2014, 21:51
Цитата(akizelokro @  9.1.2014,  20:35 Найти цитируемый пост)
Doubleton, Tripleton и Nton - теперь мой копирайт

Код

namespace {
Type foo; // singleton
std::pair<Type, Type> bar; // doubleton
const size_t N=...;
Type baz[N]; // N-ton
};

изучай)))

 smile 
иногда кажется ты пишешь не приходя в сознание, причем во все топики сразу

Автор: akizelokro 9.1.2014, 22:00
Мне, глупо говоря, первая реализация, которая пришла в голову, Doubleton было до ужасти корявое

Код

class Doubleton
{
public:
  static Doubleton & getFirstInstance()
  {
     static Doubleton first;
     return first;
  }
  static Doubleton & getSecondInstance()
  {
     static Doubleton second;
     return second;
  }
private:
  // конструкторы и деструкторы
    Doubleton() {}                                  // Private constructor
    ~Doubleton() {}
    Doubleton(const Doubleton&);                 // Prevent copy-construction
    Doubleton& operator=(const Doubleton&);      // Prevent assignment
};



И там же Tripleton и Nton. Но, когда я впендюрился недавно с 'template', я покопался в куче статей, заодно нашёл и обсуждение, почему Singleton малореальный в реальной жизни класс (потому что трудно найти в жизни неповторимые объекты), потом нашёл баг с "internal error" MS VS 2010 (да и в VS2012 его, как оказалось не поправили) при компиляции выражения template <typename T> typename struct.. А идейка с "размножением" Singleton'а до Nton'ов мне показалась жутко забавно. Может, там и enum удастся свести к простым шаблонам (да и не только целые числа).

Добавлено @ 22:09
Цитата(baldina @  9.1.2014,  21:51 Найти цитируемый пост)
иногда кажется ты пишешь не приходя в сознание, причем во все топики сразу 

Ну, это бывает, тут не спорю. Да и то не во все. В unix-программирование я не лезу, в builder и gtk я тоже не суюсь, также и в 3D графику. Ну и ещё в кое-что. Где-то я прописываюсь, потому что задачи бывают разные. Гуи в Видне, multibyte и widestrings, ActiveX, немного потоков и работы с сетями. Просто у меня бывает широкий спектр задач. Где что просекаю, хоть немного, могу вставиться.

Singleton - паттерн Майерса. Забей  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)