mardi 27 janvier 2015

Is it possible to overload a function that can tell a fixed array from a pointer?

Motivation:


Almost for fun, I am trying to write a function overload that can tell apart whether the argument is a fixed-size array or a pointer.



double const d[] = {1.,2.,3.};
double a;
double const* p = &a;
f(d); // call array version
f(p); // call pointer version


I find this particularly difficult because of the well known fact that arrays decay's to pointer. A naive approach would be to write



void f(char const* c){...}
template<size_t N> void f(char const(&a)[N]){...}


Unfortunately this doesn't work. Because in the best case the compiler determines the array call f(d) above to be ambiguous.


Partial solution:


I tried many things and the closest I could get was the following concrete code. Note also that, in this example code I use char instead of double, but it is very similar at the end.


First, I have to use SFINAE to disable conversions (from array ref to ptr) in the pointer version of the function. Second I had to overload for all possible arrays sizes (manually).


[compilable code]



#include<iostream>
template<class Char, typename = typename std::enable_if<std::is_same<Char, char>::value>::type>
void f(Char const* dptr){std::cout << "ptr" << std::endl;} // preferred it seems

void f(char const (&darr)[0] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[1] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[2] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[3] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[4] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[5] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[6] ){std::cout << "const arr" << std::endl;} // this is the one called in this particular example
// ad infinitum ...

int main(){
f("hello"); // print ptr, ok because this is the fixed size array
f(std::string("hello").c_str()); // print arr, ok because `c_str()` is a pointer
}


This works, but the problem is that I have to repeat the function for all possible values of N and using template<size_t N> gets me back to square zero, because with the template parameter the two calls get back to equal footing. In other works template<size_t N> void f(char const(&a)[N]){std::cout << "const arr" << std::endl;} doesn't help.


Is there any way to generalize the second overload without falling back to an ambiguous call? or is there some other approach?


A C++ or C++1XYZ answer is also welcome.


Aucun commentaire:

Enregistrer un commentaire