Fei Liu wrote:
Kai-Uwe Bux wrote:
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?