我试图本质上定义一个代表硬件外设的模板类,它有一些可重新映射的引脚。由于映射是在编译(或实际上是硬件原理图绘制)时定义的,我想通过模板参数引入这些定义。然而,由于每个引脚都可以独立于其他引脚进行映射,因此可能的类型集基本上是各个映射的笛卡尔积,我不确定这是否可以工作。我现在拥有的是:
enum class SPI1_NSS {
PA4,
PA15
};
enum class SPI1_SCK {
PA5,
PB3
};
template<SPI1_NSS nss_enum, SPI1_SCK sck_enum>
struct SPI_1 {
//...other stuff
struct nss;
struct sck;
};
template<SPI1_SCK sck>
struct SPI_1<SPI1_NSS::PA4, sck>::nss {
using pin = GPIOs::A::pin<4>;
};
template<SPI1_SCK sck>
struct SPI_1<SPI1_NSS::PA15, sck>::nss {
using pin = GPIOs::A::pin<15>;
};
template<SPI1_NSS nss>
struct SPI_1<nss, SPI1_SCK::PA5>::sck {
using pin = GPIOs::A::pin<5>;
};
template<SPI1_NSS nss>
struct SPI_1<nss, SPI1_SCK::PB3>::sck {
using pin = GPIOs::B::pin<3>;
};
此操作失败并显示 error: invalid class name in declaration of 'class HAL::SPI_1<HAL::SPI1_NSS::PA4, sckp>::nss'
以及其他人的类似错误。如果我删除两个模板参数之一,它就会起作用。
我期望的是,例如,给定
using spi = SPI_1<SPI1_NSS::PA4, SPI1_SCK::PB3>;
类型spi::nss::pin
将是GPIOs::A::pin<4>
和spi::sck::pin
将是GPIOs::B::pin<3>
。这种“笛卡尔特化”是否可能以某种方式实现?
我确实意识到我可以直接在 GPIO 类型上进行模板化,这有点过度设计了。然而,我从中得到的好处是枚举仅提供并保证引脚的有效选择,因此它可以提供更清晰的界面。
最佳答案
如果您的目的是专门化正交性,我会使用不嵌套在 SPI_1
中的不同元函数
namespace detail {
template<SPI1_NSS>
stuct nss;
template<>
struct nss<PA4> {
using pin = GPIOs::A::pin<4>;
};
template<>
struct nss<PA15> {
using pin = GPIOs::A::pin<15>;
};
// Same for sck
}
template<SPI1_NSS nss_enum, SPI1_SCK sck_enum>
struct SPI_1 {
//...other stuff
using nss = detail::nss<nss_enum>;
using sck = detail::sck<sck_enum>;
};
关于C++ 部分类模板针对多个参数的特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60504538/