why does the array decay to a pointer in a template function - c++

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...

Related

using std::size in a function [duplicate]

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?
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();
}

Why does the std::size on an array passed by value do not work?

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?
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();
}

Return type deduction from bytes to fundamental types [duplicate]

This might be a silly question but I would like to have it clarified none the less. Lets say I have a template function like so:
template<class T> T getValue(const char *key) const;
that returns the value as T from internal storage where it is stored under key (and possibly as type T already).
Now in order to use this I need to specify the template return type T in the function call, for example:
int value = getValue<int>("myKey");
while what I would want it to do is deduce the template argument from the context, specifically the lvalue like so:
int value = getValue("myKey"); //getValue<int>() is instantiated with int being deduced automatically from lvalue
but I am guessing that this is not possible but I am rather fuzzy as to why. I know using auto would make it impossible for the compiler to deduce the template type but why this is as well?
Template instantiation can only deduce its parameters from the arguments to given templated object(function in this case) so no, the variable type does not matter in deducing, and you either have to provide dummy argument of type T to the function or hardcode it as you did in the second to last script code(getValue<int>(...)).
There is a possible workaround using type deduction presented in the comments :
#include <iostream>
namespace byte_read {
//this is a hack to deduce the type using implicit conversion
struct type_converter {
const char* buffer;
template<typename T>
operator T() {
std::cout << "implicit convertion from " << typeid(buffer).name()
<< " to " << typeid(T).name() << std::endl;
//casting memory to the desired type
return static_cast<T>(*buffer);
}
};
type_converter getValue(const char * buffer) {
//here buffer is implicitly converted to T type using the operator T()
return {buffer};
}
}
using namespace byte_read;
int main()
{
char buffer[]{0,1,0,0 //int 256 encoded
,97 //char 'a' encoded
};
//pointer to read the buffer sequentialy
char* pos = buffer;
//pointer used to count the bytes readed
char* last_pos = pos;
int int_256 = getValue(pos);
pos+=sizeof(int);
std::cout << int_256 << " bytes readed :" << pos - last_pos << std::endl;
last_pos = pos;
char char_a = getValue(pos);
pos+=sizeof(char);
std::cout << char_a << " bytes readed :" << pos - last_pos << std::endl;
}
You can try it here

Template return type deduction from lvalue?

This might be a silly question but I would like to have it clarified none the less. Lets say I have a template function like so:
template<class T> T getValue(const char *key) const;
that returns the value as T from internal storage where it is stored under key (and possibly as type T already).
Now in order to use this I need to specify the template return type T in the function call, for example:
int value = getValue<int>("myKey");
while what I would want it to do is deduce the template argument from the context, specifically the lvalue like so:
int value = getValue("myKey"); //getValue<int>() is instantiated with int being deduced automatically from lvalue
but I am guessing that this is not possible but I am rather fuzzy as to why. I know using auto would make it impossible for the compiler to deduce the template type but why this is as well?
Template instantiation can only deduce its parameters from the arguments to given templated object(function in this case) so no, the variable type does not matter in deducing, and you either have to provide dummy argument of type T to the function or hardcode it as you did in the second to last script code(getValue<int>(...)).
There is a possible workaround using type deduction presented in the comments :
#include <iostream>
namespace byte_read {
//this is a hack to deduce the type using implicit conversion
struct type_converter {
const char* buffer;
template<typename T>
operator T() {
std::cout << "implicit convertion from " << typeid(buffer).name()
<< " to " << typeid(T).name() << std::endl;
//casting memory to the desired type
return static_cast<T>(*buffer);
}
};
type_converter getValue(const char * buffer) {
//here buffer is implicitly converted to T type using the operator T()
return {buffer};
}
}
using namespace byte_read;
int main()
{
char buffer[]{0,1,0,0 //int 256 encoded
,97 //char 'a' encoded
};
//pointer to read the buffer sequentialy
char* pos = buffer;
//pointer used to count the bytes readed
char* last_pos = pos;
int int_256 = getValue(pos);
pos+=sizeof(int);
std::cout << int_256 << " bytes readed :" << pos - last_pos << std::endl;
last_pos = pos;
char char_a = getValue(pos);
pos+=sizeof(char);
std::cout << char_a << " bytes readed :" << pos - last_pos << std::endl;
}
You can try it here

Passing char array by reference

I am passing a char array by reference but when I return from function and print the array, it displays nothing. What am I doing wrong?
#include <iostream>
using namespace std;
void func(char []);
int main()
{
char a[100];
func(a);
cout << a<<endl;
return 0;
}
void func(char *array)
{
array="Inserting data in array a";
cout << array<<endl;
}
Regards
What you can probably do is:
void func( char (& array)[10] ) {
}
According to the Spiral Rule, that is translated to: a reference (&) to an array of length 10 ([10]) characters (char).
You're not passing the array by reference (nor should you, it will do you no good here). You are passing a pointer to its first element. You then reassign that pointer to point to something else inside the function. This has no effect on the array. If you want to change the contents of the array, then you need to copy data to the place that the pointer points to. You can use strcpy or similar for that:
strcpy(array, "Inserting data in array a");
As a side comment, but a very important one. We don't need to deal with things like this in C++ anymore. That's how you do things in C. Here's how we do things in C++:
#include <string>
#include <iostream>
void func(std::string & str)
{
str = "Inserting data into the string";
std::cout << str << std::endl;
}
int main()
{
std::string a;
func(a);
std::cout << a << std::endl;
}
You can pass a pointer by reference. To do this you need to use the following syntax:
void func(char *&array)
{
// ....
}
Inside the function you use this parameter as a regular pointer. If the value that this pointer is pointing at is modified, these changes will be visible outside.
I used the answers above but I had to extend it, so I could print out the array's actual size like so:
template<size_t n> void foo(char (&array)[n])
{
// ...
std::cout << "array size: " << n << std::endl;
// ...
}
Try the following:
void function(char* MyArray)
{
MyArray = "Hello World";
std::cout << "Address of MyArray inside function: " << (void*)MyArray << std::endl;
}
int main()
{
char MyArray[10];
std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
function(MyArray);
std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
std::cin.get();
return 0;
}
With this you will see that the pointer to your array is only a copy inside the function. With assigning "Hello World" you only change the adress of the copy but not the adress of your array in the main function.
This example would actually work because this way you dont have copy of your pointer within the function:
void function(char** MyArray)
{
*MyArray = "Hello World";
std::cout << "Address of MyArray inside function: " << (void*)*MyArray << std::endl;
}
int main()
{
char* MyArray = 0;
std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
function(&MyArray);
std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
std::cin.get();
return 0;
}
But this is still bad style. When working with character arrays you should do something like this:
void function(char* MyArray)
{
strcpy(MyArray, "Hello World");
std::cout << "Address of MyArray inside function: " << (void*)MyArray << std::endl;
}
int main()
{
char* MyArray = 0;
MyArray = new char[15];
std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
function(MyArray);
std::cout << "Address of MyArray outside function: " << (void*)MyArray << std::endl;
delete [] MyArray;
std::cin.get();
return 0;
}
But as others mentioned I would use std::string and pass it by reference also instead of using character arrays. Because character arrays are unsafe compared to std::string. Like this:
void function(std::string& MyString)
{
MyString = "Hello World";
}
int main()
{
std::string MyString;
function(MyString);
std::cin.get();
return 0;
}
You are passing a pointer to an array (func (char* array)) and then inside the function you are changing the pointer's value to point to the static string.
You either need to copy the new data into the array by means of strcpy() or pass the pointer to the array by reference:
void func(char*& array); // reference to pointer
Or:
strcpy(array, "data");
Better yet use std::vector<> or std::string instead.
Reference to native array is one of the very powerful C++ weapons. Plus templates. Here is one, perhaps non trivial but still simple example.
// set all element of a given native array reference
// to the same value
// return the reference to the same array
template<typename T, size_t N, typename array_type = T[N] >
inline
array_type& /* return reference to T[N] */
all_val
( T(&arf)[N], /* arg reference to T[N] */
T val )
{
// range for() works on native arrays
// begin(arf) / end(arf)
// work as expected
for (auto & elem : arf) {
elem = val ;
}
// array can not be returned by value
// but this is allowed in standard C++
// return type is native array reference
return arf;
}
When using the above, one should think and preserve returned type as native array reference.
using charray_type = char[0xF];
charray_type charray;
// decaying to pointer to T*
// you do not want this
auto pointer_to_char = all_val(charray, '*');
// you do want this
// preserving the ref to array
charray_type& charray_ref = all_val(charray, '*');
// normal native arr usage
charray_ref[0] = '*';
assert(charray[0] == charray_ref[0]);
I think this is rather simple and unique to standard C++.
I know this post is kind of old but I recently came across a style of passing char array as a reference and implemented it in your example ..
I have no Idea why when passing a char array as a reference you use [0] as the array index but this code works .
I spend allot of time looking around the web on how to do this so maybe it helps someone
#include <iostream>
using namespace std;
void func(char arr[3]);
int main()
{
char a[3];
a[0] ='a';
a[1] ='b';
a[2] ='c';
//passing the char array as a refrence
func(&a[0]);
cout<< "checking the values outside of the func"<<endl;
cout << a<<endl;
return 0;
}
void func(char arr[3])
{
cout<<"Inserting data in array a in the function " <<endl;
cout << &arr[0]<<endl;
}
The main idea behind passing an object as a reference is to not have a copy of the object as this could use up memory resources . So in the case of char array you might have very large array so it would be inefficient to send the whole char array objet as an argument . This is why we would pass by a reference instead
error first line iostream.h ...
and secondly you are not inserting any element into array...and you are passing a in your function, you have to pass address of your array into that function, but before that rewrite the code to have something in your array