Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Шаблонная магия. Возможно ли реализовать? Перевести из С на С++ с шаблонами 
:(
    Опции темы
kuzulis
Дата 9.1.2014, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 154
Регистрация: 5.9.2007

Репутация: нет
Всего: 1



Всем доброго времени.

Имеется некое ембеддед у-во (на 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 






PM MAIL   Вверх
baldina
Дата 9.1.2014, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



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

Код

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);

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

Это сообщение отредактировал(а) baldina - 9.1.2014, 17:57
PM MAIL   Вверх
kuzulis
Дата 9.1.2014, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 154
Регистрация: 5.9.2007

Репутация: нет
Всего: 1



Да, спасибо.. Но все-равно что-то не то.. Наверное останусь на чистых С-ях и попробую переделать API на что-то человеческое.. 
PM MAIL   Вверх
baldina
Дата 9.1.2014, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



тогда достаточно одной функции
Код

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);
}


PM MAIL   Вверх
baldina
Дата 9.1.2014, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



вариации можно темплейтами (мне правда не нравится)))
Код

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);

PM MAIL   Вверх
akizelokro
Дата 9.1.2014, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



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

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

Это сообщение отредактировал(а) akizelokro - 9.1.2014, 20:43


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
baldina
Дата 9.1.2014, 21:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(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 
иногда кажется ты пишешь не приходя в сознание, причем во все топики сразу
PM MAIL   Вверх
akizelokro
Дата 9.1.2014, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Мне, глупо говоря, первая реализация, которая пришла в голову, 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 


Это сообщение отредактировал(а) akizelokro - 9.1.2014, 23:03


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0475 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.