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.