Introduction
In earlier blog, Pointer and Array in C++ – My sky (freewindcode.com), I explained that each item in an array could be accessed by pointer: That is: we have the following as equivalent:
int arr[5] = {1,2,3,4,5};
int *ptrArr = &arr;
int *(ptrArr+1) = 10; // this is the same as arr[1] = 10
Likewise, when we pass an array to a function, it is the same as passing the pointer to base array''s address to the function. "Array parameter declarations are treated as if they were pointer parameters." (Scott Meyer's Effective Modern C++)
(void myFunct(int array[]); // same as void myFunct(int *array)
However, due to array decay to pointer, the size is lost when we pass the pointer to base array's address to a function argument. Thus if we want to print out the size of the array or loop through the array, we can't.
void by_value( int* array){
cout<<"size pass by by_value "<<sizeof(*array)<<endl; // print incorrect size=4 bytes
};
void by_value_arr( int array []){
cout<<"size pass by by_value "<<sizeof(*array)<<endl; // print incorrect size=4 bytes
};
In this post, I want to extend this concept to template function: how C++ would deduce the template parameter if the argument provided is an array. The post uses explanation found in Scott Meyer's Effective Modern C++
Nomenclature
I would like to follow Mr.Scott Meyer naming conventions:
- arguments: are the expressions that we passed at the call of the function.
- parameters: are the items defined in the functions prototypes. Thus arguments are used to initialise the function's parameters.
void someFunc(Widget w); //w is the parameter, always left values
Widget wid;
someFunc(wid); // wid is the argument, could be L or R values
Template taking a by-value argument
The following programs defines a template function that take by-value parameters. In main, we invoke the template function and pass in an array or pointer to base array's address.
- Array parameter declarations are trated as if they were pointer parameters.
- The type of an array that’s passed to a template function by value is deduced to be a pointer type
- The size of the array is lost.
#include <iostream>
using namespace std;
template<typename T>void myFunct(T param){
cout<<"size pass by by_value "<<sizeof(*param)<<endl;
// param cannot be array, thus the for loop can't work
// for (auto i = std::begin(param); i != std::end(param); ++i) {
// cout << *i << " ";
// }
// cout << endl;
};
int main(){
int arr [5] = {1,2,3,4,5};
int *ptr = arr;
myFunct(arr); // print incorrect size 4 bytes
myFunct(ptr); // print incorrect size 4 bytes
return 0;
}
In line 20 and 21, the parameter is dedude to be int* t. Thus the line 7 can only print the size of the first element of the array.
Template taking a by-reference argument
The following program defines a template function that takes in be-reference parameters. If an array argument is passed to the function, the param T is deduced to be the type of the array!
#include <iostream>
using namespace std;
template<typename T> void myFunct(T& param){
cout<<"size pass by by_value "<<sizeof(param)<<endl; // size of all array
// if param is an array, then for loop can work
for (auto i = std::begin(param); i != std::end(param); ++i) {
cout << *i << " ";
}
cout << endl;
};
int main(){
int arr [5] = {1,2,3,4,5};
int *ptr = arr;
myFunct(arr); // print correct size 4 bytes
// myFunct(ptr); // cant pass a pointer;
//otherwise, for loop will not work
return 0;
}
Output:
size pass by by_value 20
1 2 3 4 5