多个参数的 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>;
};