Re: determine if a type is a free function pointer
Fei Liu wrote:
Kai-Uwe Bux wrote:
Barry wrote:
Kai-Uwe Bux wrote:
[many lines]
Good job,
boost.is_function seems to do hard coding to meet possible function
argument list length.
Makes me wonder whether there is a bug in my code. I wouldn't be
surprised.
though is_function checks function not pointer to function.
with a wrapper this should also work with function check.
template <class T>
struct is_function
{
static const bool value = is_function_pointer<T*>::value;
};
SHOW_BOOL( is_function<int(int)>::value );
SHOW_BOOL( is_function<int(int, int)>::value );
SHOW_BOOL( is_function<int(*)(int)>::value );
SHOW_BOOL( is_function<int(*)(int, int)>::value );
I actually think that the code needs some cleanup and that testing for
being a function is simpler than testing for being a function pointer.
So, I changed it the other way around. Here are the versions I added to
my library:
// is_class_type
// =============
template < typename T >
class is_class_type {
typedef char (&yes) [1];
typedef char (&no) [2];
template < typename S >
static yes check ( int S::* );
template < typename S >
static no check ( ... );
public:
static bool const value = ( sizeof( check<T>( 0 ) ) == sizeof(yes) );
}; // is_class_type
// is_pointer_type:
// ================
struct unused_type {};
template < typename T >
struct is_pointer_type {
static const bool value = false;
typedef unused_type pointee_type;
};
template < typename T >
struct is_pointer_type<T*> {
static const bool value = true;
typedef T pointee_type;
};
// is_function_type
// ================
template < typename T >
class is_function_type {
typedef char (&no) [1];
typedef char (&yes) [2];
template < typename S >
static
yes check ( S * );
template < typename S >
static
no check ( ... );
public:
static bool const value =
( ! is_class_type<T>::value )
&&
( sizeof( check<T>( * (T*)(0) ) )== sizeof( yes ) );
This statement is slightly confusing to me. So you convert the function
to function pointer, convert 0 to function pointer, dereference the
function pointer back to a function. If it was indeed a function
pointer, the first inner check struct convert it to function pointer
again. Is my understanding correct?
Yes. A commmon trick to get an object of type T for SFINAE is something like
this:
template < typename T >
class is_something {
static
T dummy ( void );
static
yes_type check ( some_magic );
static
no_type check ( ... );
public:
...
};
However, hacking on this code, I learned that functions cannot serve as
return value types. The dereferencing a T* to get a parameter of type T is
a trick to get around that.
However, there is now another problem with the code: it won't compile if T
is a reference type (since one cannot form pointer-to-reference types).
Thus, the code needs a partial specialization for reference types.
Also, since it really is just a convertibility check, one should factor that
out. Thus, I propose now:
// yes_type
// ========
struct yes_type { char dummy; };
struct no_type { yes_type a; yes_type b; };
// is_convertible
// ==============
template < typename From, typename To >
class is_convertible {
static
From* dummy ( void );
static
yes_type check ( To );
static
no_type check ( ... );
public:
static bool const value =
sizeof( check( *dummy() ) ) == sizeof( yes_type );
}; // is_convertible
// TRICKY: [why the From* and *dummy() detour]
/*
The reason is that functions cannot return function
types. Thus, in order to deal with the case where
From is a function type, we do this trick.
On the other hand, this screws up reference types.
Thus, we need to provide a partial specialization.
*/
template < typename From, typename To >
class is_convertible<From&,To> {
static
From& dummy ( void );
static
yes_type check ( To );
static
no_type check ( ... );
public:
static bool const value =
sizeof( check( dummy() ) ) == sizeof( yes_type );
}; // is_convertible
// is_function_type
// ================
template < typename T >
struct is_function_type {
static bool const value =
( ! is_class_type<T>::value )
&&
( is_convertible<T,T*>::value );
};
// T&* is not well formed:
template < typename T >
struct is_function_type<T&> {
static bool const value = false;
};
Now I know why managers don't like C++.
Huh? Isn't this fun? How could managers fail to see that?
Best
Kai-Uwe Bux