简体   繁体   中英

why does the array decay to a pointer in a template function

I don't understand why the array decays to a pointer in a template function.

If you look at the following code: When the parameter is forced to be a reference (function f1) it does not decay. In the other function f it decays. Why is the type of T in function f not const char (buff&)[3] but rather const char* (if I understand it correctly)?

#include <iostream>

template <class T>
void f(T buff) {
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;       //prints 4
}

template <class T>
void f1(T& buff) {
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;       //prints 3
}

int main(int argc, char *argv[]) {
    const char buff[3] = {0,0,0};
    std::cout << "buff size:" << sizeof(buff) << std::endl;         //prints 3
    f(buff);
    f1(buff);
    return 0;
}

It is because arrays cannot be passed by value to a function. So in order to make it work, the array decays into a pointer which then gets passed to the function by value .

In other words, passing an array by value is akin to initializing an array with another array, but in C++ an array cannot be initialized with another array:

char buff[3] = {0,0,0};
char x[3] = buff; //error 

So if an array appears on the right hand side of = , the left hand side has to be either pointer or reference type:

char *y = buff; //ok - pointer
char (&z)[3] = buff; //ok - reference

Demo : http://www.ideone.com/BlfSv

It is exactly for the same reason auto is inferred differently in each case below (note that auto comes with C++11):

auto a = buff; //a is a pointer - a is same as y (above)
std::cout << sizeof(a) << std::endl; //sizeof(a) == sizeof(char*)

auto & b = buff; //b is a reference to the array - b is same as z (above)
std::cout << sizeof(b) << std::endl; //sizeof(b) == sizeof(char[3])

Output:

4 //size of the pointer
3 //size of the array of 3 chars

Demo : http://www.ideone.com/aXcF5

Because arrays can not be passed by value as a function parameter.
When you pass them by value they decay into a pointer.

In this function:

template <class T>
void f(T buff) {

T can not be char (&buff)[3] as this is a reference. The compiler would have tried char (buff)[3] to pass by value but that is not allowed. So to make it work arrays decay to pointers.

Your second function works because here the array is passed by reference:

template <class T>
void f1(T& buff) {

// Here T& => char (&buff)[3]

To quote from spec, it says

(14.8.2.1/2) If P is not a reference type: — If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of A for type deduction; otherwise

So, in your case, It is clear that,

template <class T>
void f1(T& buff) {
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;       //prints 3
}

doesn't decay into pointer.

Because functions can't have arrays as arguments. They can have array references though.

The reason basically boils down to type deduction when matching the different overloads. When you call f the compiler deduces the type to be const char[3] which then decays into const char* because that's what arrays do . This is done in the same exact way that in f(1) the compiler deduces T to be int and not int& .

In the case of f1 because the argument is taken by reference, then the compiler again deduces T to be const char[3] , but it takes a reference to it.

Nothing really surprising, but rather consistent if it were not for the decay of arrays to pointers when used as function arguments...

In f1() , Size 4 is size of pointer which is 4 bytes. because in this function you have a pointer to the array.

In f1() , you have that array by reference(or another name), and it is real array size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM