Частичная специализация шаблона класса C ++ для нескольких параметров - PullRequest
2 голосов
/ 03 марта 2020

Я пытаюсь по существу определить класс шаблона, который представляет аппаратное периферийное устройство, у которого есть некоторые переназначаемые выводы. Поскольку сопоставление определяется во время компиляции (или собственно аппаратной схемы c), я хотел бы перенести эти определения через параметры шаблона. Тем не менее, поскольку каждый из выводов может быть отображен независимо от других, набор возможных типов является в основном декартовым произведением отдельных отображений, и я не уверен, что это можно заставить работать. Теперь у меня есть:

     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 напрямую, и это немного переоценивается. Однако преимущество, которое я получил бы от этого, состоит в том, что enum предоставляет и гарантирует только допустимые варианты выбора для выводов, поэтому он обеспечивает более четкий интерфейс.

1 Ответ

3 голосов
/ 03 марта 2020

Если вы хотите специализировать ортогональность, я бы использовал различные мета-функции, которые не вложены в 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>;
};
...