Why does the std::size()
do not work on a statically allocated array passed by value?
void print_elemTab(int tab[])
{
// ...
int size = std::size(tab); //error
// ...
}
void test_tab()
{
const int TAB_SIZE = 5;
int tab[TAB_SIZE] = {};
// ...
cout << std::size(tab) << std::endl; //print 5
print_elemTab(tab);
// ...
}
I am printing the size and then I am passing the tab
in the sub-function print_elemTab()
where I am using std::size()
again.
I get no matching function error, so I wonder why std::size()
works the first time in test_tab()
and not in print_elemTab()
Do I have to pass it by reference? And so how do I make it but for an array of any length?
Or do I have to make it in another way because of something that I am not aware of?
std::array is a container that encapsulates fixed size arrays. This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member. Unlike a C-style array, it doesn't decay to T* automatically.
Pass an array by value to a function in C/C++ However, arrays in C cannot be passed by value to a function, and we can modify the contents of the array from within the callee function. This is because the array is not passed to the function, but a copy of the pointer to its memory address is passed instead.
Passing the array size tells the function where the bounds are so you can choose not to go beyond them.
Answer: An array can be passed to a function by value by declaring in the called function the array name with square brackets ( [ and ] ) attached to the end. When calling the function, simply pass the address of the array (that is, the array's name) to the called function.
Array designators used in expressions are implicitly converted (with rare exceptions as for example using them in the sizeof
operator) to pointers to their first elements.
So in this call
print_elemTab(tab);
the argument expression has the type int *
.
On the other hand, a function parameter having an array type is adjusted by the compiler to pointer to the element type of the array.
So for example these function declarations
void print_elemTab(int tab[]);
void print_elemTab(int tab[5]);
void print_elemTab(int tab[100]);
declare the same one function and are equivalent to the following declaration
void print_elemTab(int *tab);
You nay even include all these declarations in your program though the compiler can issue a message that there are redundant declarations.
Hence within the function you are dealing with a pointer of the type int *
. And sizeof( int * )
is usually equal to 4
or 8
depending on the used system.
If you have such a declaration you should change it specifying a second parameter that will keep the number of elements in the passed array like
void print_elemTab(int *tab, size_t n );
And the function can be called like
print_elemTab(tab, std::size( tab ) );
Another approach is to pass the array by reference. In this case you should declare a template function for example like
template <size_t N>
void print_elemTab( int ( &tab )[N] );
Within the function you can either directly use the template parameter N
as the number of elements in the array. Or you can apply the same standard C++ function std::size
to the array.
Or the function can be even more general declared with a second template type parameter like
template <typename T, size_t N>
void print_elemTab( T ( &tab )[N] );
Another approach is to declare the function like
template <typename Container>
void print_elemTab( Container &container );
In this case you also may apply the standard function std::size
to the parameter container.
Do I have to pass it by reference? And so how do I make it but for any array of any length?
Yes, passing it by reference would be one option.
template<std::size_t n>
void print_elemTab(int (&tab)[N]) // const int (&tab)[N], if the elements won't be modified
{
std::cout << N << "\n"; // where you can directly get the size `N`
}
Or like simple templated function as follows
template<typename T>
void print_elemTab(T& tab)// const T& tab, if the elements won't be modified
{
const auto size = std::size(tab);
std::cout << size << "\n";
}
Another option is to deduce the array to its actual type. In your case, the tab
has the type int[5]
. The compiler can deduce to its actual type(other than decaying to pointer) if you perfectly forward via a template function.
#include <iostream>
#include <array>
template<typename T>
void print_elemTab(T&& tab)
{
const auto size = std::size(tab); // now you can do std::size() on the int[size]
std::cout << size << "\n";
}
Yes, you have to pass it by reference because it's decayed to a pointer on passing it to your function. and to make the function accept any size I suggest to use a function template as follows
#include <iostream>
template<size_t n>
void print_elemTab(int (&tab)[n])
{
int size = std::size(tab);
std::cout << size << "\n";// or just std::cout << n; and ignore the previous line
}
void test_tab() {
const int TAB_SIZE = 5;
int tab[TAB_SIZE] = {};
std::cout << std::size(tab) << std::endl; //print 5
print_elemTab(tab);
}
int main(){
test_tab();
}
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