【问题标题】:How to call multiple templated functions with a single call?如何通过一次调用调用多个模板化函数?
【发布时间】:2018-12-06 22:02:41
【问题描述】:

我正在开发一个程序(模拟器),我需要在其中访问模拟机器的内存映射。这是使用模板函数完成的(读取)。
此函数根据模板化参数返回数据大小(即read(0x10)将从内存地址0x10返回8位数据,read(0x20) 将从内存地址 0x20) 等返回 32 位数据。
这是使用 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);

? 我认为可以使用模板模板参数来完成,但我对模板不够熟练,无法了解如何操作...

这是完整的例子,可以测试here

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

【问题讨论】:

  • 如果有的话,initializeHandler(0x00, 0xFF, readDummy&lt;uint8_t&gt;); 可以工作并且已经比你正在做的更好。
  • 好电话,我没想到这个参数是从另一个参数推导出来的……谢谢你的信息!

标签: c++11 templates c++14 c++17


【解决方案1】:

您可以将readDummyreadRom 转换为可转换为ReadType&lt;T&gt; 的类型,并使用如下折叠表达式:

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

【讨论】:

  • 按我想要的方式工作......谢谢!我现在更好地理解它是如何工作的。我必须根据我的代码调整它,因为我提供的是精简版,但我现在知道该去哪里了。再次感谢:)
  • 我用“写”部分更新了代码,你可以看到here。显然,当您同时具有“读取”和“写入”版本时,不可能自动推断出正确的 initialize 实例,因为我遇到了替换失败...如果我声明这两个函数,它就可以正常工作作为初始化读取和初始化写入。你知道是否有办法修复替换失败以便对两个函数有相同的声明?谢谢!
  • @Runik 告诉我this 是否是您所需要的。
  • 效果很好,但我还有一个问题:ReadType 被用作 initialize 的模板参数,它也被称为 using WriteType 具有不同的签名......它显然有效,但如何?我想了解 :) 谢谢!
  • @Runik 我在this上加了一些cmets,希望你现在明白了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多