This is a way to capture the size of an array parameter. Arrays have a type of T[N]
that often can decay to T*
.
#include <iostream>
template <int N>
void foo(const char(&str)[N]){
for(int i=0;i<N;++i)
std::cout<<str<<' ';
}
void foo(const char* str){
//for(int i=0;i<??;++i)
}
void bar(const char* str, int n){
for(int i=0;i<n;++i)
std::cout<<str<<' ';
}
int main(){
const char str[] = "Hello";//type is const char[6]
const char* str2 = str; //Decay
// const char str3[] = str; (6)
int n = sizeof(str)/sizeof(str[0]);
foo(str);// (1) Calls foo<6>
foo(str2);// (2) Must call foo(const char*) which is useless
bar(str, n); // (3) Array can decay
bar(str2, n); // (4) Same as (3) - bar can be used with all arrays
bar(str2, 10); // (5) Buffer overrun
}
The above example shows the usage and limitation of the templated approach. The advantage is that you don't have to pass the size separately so it will be always be correct. The big disadvantage is that the decay process is irreversible so the function then becomes useless - (2) cannot call the template.
The template is handy but most arrays decay to pointers rather quickly by passing them around via bar
- which was the only way in C - or simply because their size is not known at compile time - malloc, new
. Another problem is that both in C and C++ (6) is invalid - there's no implicit way to copy an array. So the bar
approach is much more common but it requires extra care to pass the correct size. The correct c++ way is to use std::vector
or std::array
unless they are proven to be a bottleneck.