Array Argument Deducing in Template Parameter

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

Leave a Reply

Your email address will not be published. Required fields are marked *