I have a template class where the template parameter corresponds to the size of an array within the class.
template <typename T, size_t S>
class Example {
...
private:
T values[S];
};
This leads to an expected warning: “ISO C++ forbids zero-size array.” In my case, something like Example<uint8_t, 0>
would make no sense, and I would like to prevent the code containing Example<..., 0>
from compiling.
How do I express in C++ that S
should be superior or equal to one?
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Every template is parameterized by one or more template parameters, indicated in the parameter-list of the template declaration syntax: template < parameter-list > declaration Each parameter in parameter-list may be: a non-type template parameter;
A template argument for a type template parameter must be a type-id, which may name an incomplete type: A template argument for a template template parameter must be an id-expression which names a class template or a template alias. When the argument is a class template, only the primary template is considered when matching the parameter.
When the name of a non-type template parameter is used in an expression within the body of the class template, it is an unmodifiable prvalue unless its type was an lvalue reference type, or unless its type is a class type (since C++20) .
If the default is specified for a template parameter of a primary class template , primary variable template, (since C++14)or alias template, each subsequent template parameter must have a default argument, except the very last one may be a template parameter pack.
The C++20 way is
template <typename T, size_t S> requires (S > 0)
class Example
{
// ...
};
You're really trading in one compiler diagnostic for another, but here's one approach:
template <typename T, size_t S,
typename=std::enable_if_t< (S>0) >>
Alternatively: use static_assert
to get a friendlier error message:
template <typename T, size_t S>
class Example {
private:
static_assert(S>0);
T values[S];
};
You'll get a friendlier error message however this template will still participate in overload resolution, which in some edge cases may be undesirable.
T values[0];
is alread ill-formed. Thus, if you configure the compiler to not use language extensions, then it won't compile.
Or, you can use a static_assert
.
If there are situations where S being zero are valid. You can add a specialization for that case.
template<typename T, size_t S>
class Example {
...
private:
T values[S];
};
template<typename T>
class Example<T, 0> {
...
private:
// Don't need an array here for this case.
};
This will keep your code compiling in situations where you have heavy templating that makes S zero.
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