Как вызвать несколько шаблонных функций одним вызовом? - PullRequest
0 голосов
/ 07 декабря 2018

Я работаю над программой (эмулятором), где мне нужно получить доступ к карте памяти эмулируемой машины.Это делается с использованием шаблонной функции (чтение).
Эта функция возвращает размер данных в зависимости от шаблонного параметра (т. Е. 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;
}

1 Ответ

0 голосов
/ 07 декабря 2018

Вы можете превратить readDummy и readRom в типы, конвертируемые в ReadType<T>, и использовать выражения складывания следующим образом:

template<typename T>
struct readDummy
{
    operator ReadType<T>() const {
        return [] (const uint32_t addr) -> T {
            return sizeof(T{});
        };
    }
};

template<typename T>
struct readRom
{
    operator ReadType<T>() const {
        return [] (const uint32_t addr) -> T {
            return sizeof(T{})*2;
        };
    }
};


template <template <class> class ReadType, class... T>
auto initialize(uint32_t begin, uint32_t end)
{
    (initializeHandler<T>(begin, end, ReadType<T>{}), ...);
}

initialize<readDummy, uint8_t, uint16_t, uint32_t>(0x00, 0x0FF);
initialize<readRom, uint8_t, uint16_t, uint32_t>(0x60, 0xFF);
...