Я работаю над программой (эмулятором), где мне нужно получить доступ к карте памяти эмулируемой машины.Это делается с использованием шаблонной функции (чтение).
Эта функция возвращает размер данных в зависимости от шаблонного параметра (т. Е. read (0x10) вернет 8 бит данных с адреса памяти 0x10, read (0x20) вернет 32 бита данных с адреса памяти 0x20) и т. Д.
Это делается с использованием 3 массивов указателей на функции ( read_8_handler_ , read_16_handler_ , read_32_handler_ ), связывая каждый адрес с определенной функцией.
Инициализация этих массивов выполняется 3 раза, вызывая initializeHandlers для каждой связанной функции:
// default handlers
initializeHandler<uint8_t>(0x00, 0xFF, readDummy<uint8_t>);
initializeHandler<uint16_t>(0x00, 0xFF, readDummy<uint16_t>);
initializeHandler<uint32_t>(0x00, 0xFF, readDummy<uint32_t>);
// rom handlers
initializeHandler<uint8_t>(0x60, 0x6F, readRom<uint8_t>);
initializeHandler<uint16_t>(0x60, 0x6F, readRom<uint16_t>);
initializeHandler<uint32_t>(0x60, 0x6F, readRom<uint32_t>);
Это приводит к большой избыточности, так как каждый обработчик должен использовать 3 строки для инициализации.
Итак, мой вопрос: могу ли я использовать одну строку для инициализации одного обработчика, не предоставляя аргументы шаблона,как это:
initializeHandler(0x00, 0xFF, readDummy);
initializeHandler(0x60, 0x6F, readRom);
?Я думаю, что это можно сделать с помощью параметров шаблона шаблона, но я недостаточно свободно разбираюсь в шаблонах, чтобы узнать, как это сделать ...
Вот полный пример, который можно проверить здесь
#include <iostream>
#include <cstdlib>
#include <array>
#include <tuple>
template <typename R, typename ...ARGS> using function = R(*)(ARGS...);
template<typename T> using ReadType = function<T, const uint32_t>;
template<class ReadType> using ReadHandlerType = std::array<ReadType, 0x100>;
template<typename T> using ReadHandler = ReadHandlerType<ReadType<T>>;
ReadHandler<uint8_t> read_8_handler_;
ReadHandler<uint16_t> read_16_handler_;
ReadHandler<uint32_t> read_32_handler_;
template<typename T>
T readDummy( const uint32_t addr) {
return sizeof(T{});
}
template<typename T>
T readRom( const uint32_t addr) {
return sizeof(T{})*2;
}
template<typename T>
void initializeHandler(uint32_t begin,
uint32_t end,
ReadType<T> func) {
auto t = std::tie(read_8_handler_, read_16_handler_, read_32_handler_);
for (uint32_t current = begin; current <= end; ++current) {
auto& handler = std::get < ReadHandler<T>& >(t);
handler[current & 0xFF] = func;
}
}
template<typename T>
T read(const uint32_t addr) {
auto& handler = std::get < ReadHandler<T>& >(std::tie(read_8_handler_, read_16_handler_, read_32_handler_));
return handler[addr](addr);
}
int main()
{
initializeHandler<uint8_t>(0x00, 0xFF, readDummy<uint8_t>);
initializeHandler<uint16_t>(0x00, 0xFF, readDummy<uint16_t>);
initializeHandler<uint32_t>(0x00, 0xFF, readDummy<uint32_t>);
initializeHandler<uint8_t>(0x60, 0x6F, readRom<uint8_t>);
initializeHandler<uint16_t>(0x60, 0x6F, readRom<uint16_t>);
initializeHandler<uint32_t>(0x60, 0x6F, readRom<uint32_t>);
std::cout << read<uint16_t>( 0x20) << std::endl;
std::cout << read<uint16_t>( 0x60) << std::endl;
}