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