多个参数的 C++ 部分 class 模板特化
C++ partial class template specialization over multiple parameters
我试图从本质上定义一个模板 class 来代表硬件外围设备,它有一些可重映射的引脚。由于映射是在编译(或实际上是硬件示意图)时定义的,我想通过模板参数引入这些定义。然而,由于每个引脚都可以独立于其他引脚进行映射,因此可能的类型集基本上是各个映射的笛卡尔积,我不确定这是否可行。我现在拥有的是:
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>
。这种"Cartesian specialization"有可能吗?
我意识到我可以直接在 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>;
};
我试图从本质上定义一个模板 class 来代表硬件外围设备,它有一些可重映射的引脚。由于映射是在编译(或实际上是硬件示意图)时定义的,我想通过模板参数引入这些定义。然而,由于每个引脚都可以独立于其他引脚进行映射,因此可能的类型集基本上是各个映射的笛卡尔积,我不确定这是否可行。我现在拥有的是:
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>
。这种"Cartesian specialization"有可能吗?
我意识到我可以直接在 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>;
};