When reading a wiki page, I found this sample code
template <class T>
struct is_pointer
{
template <class U>
static char is_ptr(U *); #1
template <class X, class Y>
static char is_ptr(Y X::*);
template <class U>
static char is_ptr(U (*)()); #2
static double is_ptr(...);
static T t;
enum { value = sizeof(is_ptr(t)) == sizeof(char) };
};
To me, #2 is just a specialization of #1, so it seems superfluous.
Did I make something wrong? What would it be like in the eyes of C compilers?
CodePudding user response:
template <class U> static char is_ptr(U *);: is_ptr is a function taking a pointer to U (without a name) and returning a char.
template <class U> static char is_ptr(U (*)());: is_ptr is a function taking a function pointer (without a name), which gets no parameters and returns a U, and returns a char.
So, one gets a pointer to a U and the other a function pointer, which returns a U.
CodePudding user response:
To me, #2 is just a specialization of #1, so it seems superfluous.
An overload, not a specialization. And yes, it is superfluous. In a template accepting U* for a parameter, U can resolve to an entire function type. It's what makes is_pointer<int(*)(char)>::value be true, despite the fact int(*)(char) will not match the overload #2.
Did I make something wrong?
Since you did not make this code yourself, I don't believe you did. You correctly surmised there's a redundancy.
What would it be like in the eyes of C compilers?
It would be an overload that gets picked for the specific case of checking a function pointer type that accepts no arguments. It conveys no interesting information compared to the U* overload, and can be removed.
It's possible this implementation was added to get around a compiler bug (where said function pointer types were not correctly handled). Modern compilers handle said function pointers correctly even if the superfluous overload is removed.
