Цитата(Сергей Борщ @ May 27 2010, 14:26)

Вот-вот. 10 надо подставлять вручную, что убивает всю красоту.
Не обязательно. :-)
В оригинале (
C++ Interrupts ) использовался макрос:
Код
#define CLASS_IRQ(name, vector) \
static void name(void) asm(__STRINGIFY(vector)) \
__attribute__ ((signal, __INTR_ATTRS))
Он рабочий, как я понял, только с некоторыми оговорками:
- при описании тела ф-ции необходимо добавить перед ней 'extern "C"'
- заменить "YYYYYYY_XXX_vect" (например, TIMER0_OVF_vect) на "__vector_XX"
Второй пункт можно реализовать через макросы (что-то навроде #define TIMER0_OVF_vect __vector_XX)
Мой вариант был лишь концептом, специально сделанным максимально прозрачным, для упрощения понимания. Отполировать до блеска его всегда можно, лишь бы рабочим был.
Да и скрыто это будет от енд-юзера... Код получается практически повторно используемым. Фактически, как это нынче модно называть, Framework'ом. Таким образом можно охватить фактически всю перефирию контроллера и код станет вполне повторно используемым. Но здесь есть одна засада! Начну немного издалека.
В Delphi и .NET, компоненты на форме делегируют обработку событий методам формы, что весьма удобно и выглядит красиво.
Хотелось бы реализовать что-то подобное. Т.е. класс таймера, к примеру реагирует на прерывание от него и, например, перезагружает регистр счетчика необходимым значением, на этом его функции обработки прерывания заканчиваются. Сама же обработка события делегируется другому объекту для обработки и следованию общей логики выполнения программы. Сама идея не нова -- паттерн command из книжки GoF. Лично мне очень понравилась реализация этого паттерна от Александреску. После того, как продрался через его описание в книжке. ИМХО, объяснять Александреску нихрена не умеет! Вот только есть нюанс, любые реализации этого паттерна используют виртуальные ф-ции, что тянет за собой доп код и мешает оптимизации. В случае Александреску, получается пара ф-ций "пересылки" аргументов к месту назначения. Даже после оптимизации все равно останется косвенный переход по VTable, т.ч. "сквозной" оптимизации не получится. И если для ARM'ов еще можно махнуть рукой или плюнуть (нужное подчеркнуть), то, например, для ATmega48, плеваться придется много и долго...
Есть вариант решения с использованием шаблонов. Данный пример для "большой" машины и только в целях иллюстрации принципа (не надо мне потом предъявлять по поводу использования std::list на ATmega48! :-).
Код
/*
* Command.h
*
* Created on: 26.05.2010
* Author: damon
*/
#ifndef COMMAND_H_
#define COMMAND_H_
#include <iostream>
#include <list>
#include <string>
template< class Handlers >
class Command: public Handlers
{
public:
Command( ) { }
void Signal( int sign )
{
Handlers::OnSignal( sign );
}
};
class CommandHandler
{
private:
std::string str_;
public:
CommandHandler( char *str )
{
str_ = str;
}
void Print( int val )
{
std::cout << str_ << std::endl << "\t Полученное значение: " << val << std::endl;
}
};
class CommandSwitcher
{
private:
std::list< CommandHandler * > handlers_;
public:
void AddHandler( CommandHandler *handler )
{
handlers_.push_back( handler );
}
void operator+=( CommandHandler *handler )
{
AddHandler( handler );
}
void DelHandler( CommandHandler *handler )
{
handlers_.remove( handler );
}
void operator-=( CommandHandler *handler )
{
DelHandler( handler );
}
void OnSignal( int sign )
{
std::for_each( handlers_.begin( ), handlers_.end( ), bind2nd( mem_fun( &CommandHandler::Print ), sign ) );
}
};
#endif /* COMMAND_H_ */
Код
//main.cpp
#include "Command.h"
int main()
{
Command< CommandSwitcher > command;
CommandHandler firstHandler( ( char * ) "First handler" );
CommandHandler secondHandler( ( char * ) "Second handler" );
CommandHandler thirdHandler( ( char * ) "Third handler" );
command += &firstHandler;
command += &secondHandler;
command += &thirdHandler;
command.Signal( 10 );
std::cout << std::endl;
command -= &firstHandler;
command.Signal( 1 );
return 0;
}
Таким образом вся логика "коммутации" сигнала о событии сосредоточена в классе CommandSwitcher, который никоим образом не зависит от класса Command. При этом, при использовании класса Command в другом проекте не понадобится вносит в него никаких изменений! Меняться будет только CommandSwitcher!
При этом виртуальные ф-ции не используются, а поскольку шаблонные методы описываются в хидере, есть надежда на их "сквозную" оптимизацию, что благотворно скажется на размере и скорости прошивки контроллера!