The purpose of passing any raw function pointer is that the caller has some idea about:
- What he points to.
- How much does this indicate.
C-style strings have the latter assumption as input parameters, since it is assumed that "how much" is considered to be a char in the null terminator.
But what if you don't pass a C style string? What if it's just a sequence of values of zero or more char ? Well, if so, then:
void f(const char *s) {
The logical conclusion would be to do this:
void f(const char *s, std::size_t N) {
and this is not uncommon, although a potential point of error, if the caller gives us the wrong length (never say never).
But what if there was a way to destroy this data from the actual type of the variable passed to the function using a deduction through a template parameter without a type? What if the caller refers to a fixed array?
template<std::size_t N> void f(const char(&ar)[N]) {
Now we know both points on our list: “what” and “how much”. In addition, we can now provide both the template function and the overload, and both worlds are available to us:
// length specified implementation void f(const char *s, std::size_t N) { // caller passed N } // fixed buffer template wrapper template<std::size_t N> void f(const char(&ar)[N]) { f(ar,N); // invokes length-specified implementation from above. }
And both of them will work:
int main() { char buff[3]; f(buff,3); f(buff); }
So how is that good? Because the following will mean a compiler error, since the corresponding implementation cannot be found:
int main() { char buff[3]; const char *ptr = buff; f(ptr);
In general, this is a general technique that helps to provide bullets to both points on our list: “what” and “how much”, without the need to use sizeof(ar)/sizeof(*ar) long time each time you use a fixed -length own array as your input parameter.
Good luck.