Reputation: 2787
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;
}
Upvotes: 11
Views: 3211
Reputation: 361362
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
Upvotes: 16
Reputation: 17557
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.
Upvotes: 4
Reputation: 264381
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]
Upvotes: 10
Reputation: 208333
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...
Upvotes: 1
Reputation: 81349
Because functions can't have arrays as arguments. They can have array references though.
Upvotes: 1