I want to write templates to construct let's say an input port. That can be done from either a single input-output port, or from a list of input pins. I prefer those templates to have the same name. I have concepts for both an input-output port and for input pins. I can write
template< typename... arguments >
struct port_in ....
template< pin_in T >
struct port_in<> ....
But now the list version will accept any type. I can check that in the implementation, but that will degrade the error message the user gets when he passes types that are not suited. Can I somehow restrict the list to one type, yet allow a single template parameter of the other type?
If two template class names have the same template name and if their arguments have identical values, they are the same class. In this example, the template argument size becomes a part of the template class name.
C++ on the other hand has no such restriction. Template parameter types can be any type compatible with the operations they are used with. There doesn't have to be a common base class. This is similar to Python's "Duck Typing," but done at compile time.
In the body of the template declaration, the name of a type parameter is a typedef-name which aliases the type supplied when the template is instantiated. There is no difference between the keywords class and typename in a type template parameter declaration.
A class template does not need to have a type argument if it has non-type arguments. For example, the following template is a valid class template: Again, these two declarations refer to distinct classes because the values of their non-type arguments differ.
If you want to ensure that users always get a reasonable error message, then you need to constrain the base template. Assuming your existing concepts are named InputPin
and InputOutputPort
, you could constrain the base template to accept either a sequence of input pins or a single input/output port as follows:
template<class... Ts>
concept bool AllInputPins = (InputPin<Ts> && ...);
template<class... Ts>
concept bool OneInputOutputPort = sizeof...(Ts) == 1 && (InputOutputPort<Ts> && ...);
template <class... Args>
requires AllInputPins<Args...> || OneInputOutputPort<Args...>
struct port_in {
// ...
};
If the list version is supposed to take numbers you could make it:
template<uint16_t ... Ports>
struct port_in ....
I'm not sure there is a clean way to do this if it can take non-integers and you want an actual type list (that is not all the arguments need be of the same type). If you can require that all the types be the same I think you could do something like:
template<typename T, std::enable_if_t<T> * = nullptr>
struct port_in_base{};
template<typename T, T ... ports>
struct port_in : port_in_base<T> ....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With