Reputation: 871
I'm trying to essentially define a template class that represents a hardware peripheral, which has some remappable pins. Since the mapping is defined at compile (or actually hardware schematic drawing) -time, I'd like to bring these defines in via template parameters. However, since each of the pins can be mapped independently of the others, the set of possible types is basically a cartesian product of the individual mappings, and I'm not sure if this can be made to work. What I have now is:
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>;
};
This fails with error: invalid class name in declaration of 'class HAL::SPI_1<HAL::SPI1_NSS::PA4, sckp>::nss'
and similar errors for the others. It works if I remove one of the two template parameters.
What I'd expect to have is that, for example, given
using spi = SPI_1<SPI1_NSS::PA4, SPI1_SCK::PB3>;
the type spi::nss::pin
would be GPIOs::A::pin<4>
and spi::sck::pin
would be GPIOs::B::pin<3>
. Is this kind of "Cartesian specialization" possible somehow?
I do realize that I could just template on the GPIO types directly, and this is a bit overengineered. However, the advantage I'd get from this is that the enum provides and guarantees only the valid choices for the pins, so it makes for a clearer interface.
Upvotes: 2
Views: 93
Reputation: 170044
If your intent is to specialize orthogonality, I'd use distinct meta-functions that aren't nested withing 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>;
};
Upvotes: 3