It is possible to know the size of an array passed as an argument to a function using templates and type deduction:
template <size_t N>
void imprimeMenu(const char *(&menuOpc)[N])
{
int Length = N;
printf("Length: %i\n", Length);
for (int i = 0; i < Length; ++i)
printf("%i - %s\n", i + 1, menuOpc[i]);
}
Notice how the parameter differs with your:
template <size_t N>
void imprimeMenu(const char *(&menuOpc)[N])
In this case, we have a parameter menuOpc
of the kind reference to an array of const char *
fixed-size N
. When passing your array opcSalgados
for the function (as shown below), this template will deduce parts of the parameter type that are known at compiler time.
imprimirMenu(opcSalgados);
So given any size M
of an array, type deduction will conclude that the value of N
needs to be equal to M
, so that the function template instance is a suitable candidate for the argument types.
It is possible to simplify this code using the container Std::array, which is effectively a fixed size array, but with a better interface:
std::array<const char *, 6> opcSalgados = {
"Pastel", "Mini pizza",
"Coxinha", "Pao de queijo",
"Pao de frango com queijo", "Pao de carne"
};
template <size_t N>
void imprimeMenu(std::array<const char *, N> menuOpc)
{ /* mesma implementação… */ }
The disadvantage of using std::array
is that its size needs to be specified in the template parameter (as seen in the code: std::array<const char *, 6>
). If your compiler supports C++17, this problem goes away with the new deduction notes:
std::array opcSalgados = {
"Pastel", "Mini pizza",
"Coxinha", "Pao de queijo",
"Pao de frango com queijo", "Pao de carne"
};
The template parameters of std::array
are automatically deducted by arguments passed to the constructor.
In any case, when you know the fixed size of the array (be it a primitive array, or the container std::array
), it is possible to use the loop for
based on intervals (or Range-based for loop) from C++11:
template <size_t N>
void imprimeMenu(const char *(&menuOpc)[N]) // ou std::array<const char *, N>
{
std::printf("Length: %zu\n", N);
int i = 1;
for (auto opcao : menuOpc)
std::printf("%i - %s\n", i++, opcao);
}
Where auto
shall be deducted for the type of menuOpc elements (in this case, const char *
). That variation of for
ensures that you will never have problems like accessing indexes out of array size etc.
If you need to pass other arrays with different element types, just enter one more generic type in the template parameters and use it instead of const char *
:
template <typename T, size_t N>
void imprimeMenu(T(&menuOpc)[N]) // ou std::array<T, N>
Note, however, that now the implementation needs to meet any type that is deduced for T
:
template <typename T, size_t N>
void imprimeMenu(T(&menuOpc)[N]) // ou std::array<T, N>
{
std::cout << "Length: " << N << '\n'; // Aqui.
int i = 1;
for (auto opcao : menuOpc)
std::cout << i++ << " - " << opcao << '\n'; // Aqui.
}
Thank you, your example worked correctly. I have a question, is it possible to use, more than one template in this case? In the case of a different variable, it can be several types(double, float, int, long, const long). An example of what I am trying to do (the example is wrong), if it is not clear: https://paste.ofcode.org/343rbSDDTse4zxafLW7sVRy
– cYeR
@cYeR You can enter one more generic type in the template parameters and use it instead of
const char *
. I will edit the answer as per.– Mário Feroldi
Thank you, I implemented in my functions according to your example and worked perfectly.
– cYeR