Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a C++ template match (only) a list of one type, or a single other type?

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?

like image 823
Wouter van Ooijen Avatar asked Dec 15 '17 21:12

Wouter van Ooijen


People also ask

How to tell if two template class names are the same?

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.

What is the difference between C++ and C++ template parameters?

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.

What is the difference between class and typename in a template?

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.

Does a class template need to have a type argument?

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.


2 Answers

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 {
  // ...
};
like image 117
Casey Avatar answered Sep 30 '22 03:09

Casey


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> ....
like image 41
SoronelHaetir Avatar answered Sep 30 '22 03:09

SoronelHaetir