Kai-Uwe Bux said:
Victor said:
Fei Liu wrote:
Victor Bazarov wrote:
Fei Liu wrote:
I am trying to experiment with typetraits such that I can determine
if a type is a free function pointer type.
What's a "free function pointer"? One without the arguments? One
that is not a member of any class? One that is not a non-static
member?
non class member function pointer. it could take arbitrary number of
arguments.
[..something that works for no args or one arg..]
But add the following code:
void foo(int, int) {}
typedef int (*foo_fp3)(int, int);
cout << "result: " << typetraits<foo_fp3>::result << endl;
result is 0 although I expect it to be 1. I have searched the web,
books, etc. But I haven't found a generic technique to achieve what I
wanted.
[..]
I would be curious to see if it's something that cannot be solved
using currently available methods. AFAIK there are no conversions
specific to function pointers only, and the new proposed additions
to the Standard are specifically designed not to distinguish the
functors and functions.
If I missed something, the direction to think is to find something
specific to a function, like inability to declare a reference to
it, which can then be exploited in a SFINAE solution...
I don't know if the following is guaranteed to work, or whether there is a
bug in g++. I also have no idea why it should work :-( Anyways, it appears
that there is a way (on my platform) to distinguish non-pointers from
pointer and (among pointers) function pointer from non-function pointers.
I would welcome comments as to how this might work or why g++ could be
wrong. Should it happen to be correct, maybe the original question can be
solved along these lines.
template < typename T >
struct is_ptr {
static const bool value = false;
};
template < typename T >
struct is_ptr<T*> {
static const bool value = true;
};
template < typename T >
class is_fct_ptr {
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 =
sizeof( check<T>( * T(0) ) )== sizeof( yes );
}; // is_fct_ptr
typedef int (*fct_ptr) ( int, int );
typedef int * non_fct_ptr;
#include <iostream>
#include <iomanip>
#define SHOW_BOOL(expr) \
std::cout << #expr << " = " << std::boolalpha << (expr) << '\n';
int main ( void ) {
SHOW_BOOL( ! is_ptr<int>::value );
SHOW_BOOL( is_ptr<non_fct_ptr>::value );
SHOW_BOOL( is_ptr<fct_ptr>::value );
SHOW_BOOL( is_fct_ptr<fct_ptr>::value );
SHOW_BOOL( ! is_fct_ptr<non_fct_ptr>::value );
}
Actually, now I think I understand how it works. For function types F there
is a conversion from F to F*. This is not present for other types (unless a
class creates a conversion operator. The following confirms the suspicion:
class X {
public:
operator X* ( void ) {
return ( this );
}
};
struct Y {
};
SHOW_BOOL( is_fct_ptr<Y*>::value );
SHOW_BOOL( is_fct_ptr<X*>::value );
Now, with these insights, one can devise a scheme to check whether T is a
function pointer: (a) check whether it is a pointer, (b) check whether it
is a pointer to a class type, and (c) check whether the type *T supports a
conversion to T. The answers to (a) and (c) must be positive and the answer
to (b) negative. There is a SFINAE check for whether a type is a class
type. Putting it all together yields:
struct no_type {};
template < typename T >
struct is_pointer_type {
static const bool value = false;
typedef no_type pointee_type;
};
template < typename T >
struct is_pointer_type<T*> {
static const bool value = true;
typedef T pointee_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
template < typename T >
struct is_pointer_to_class {
static const bool value = false;
};
template < typename T >
struct is_pointer_to_class<T*> {
static const bool value =
is_class_type<T>::value;
};
template < typename T >
class supports_conversion_to_pointer {
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 =
sizeof( check<T>( * T(0) ) )== sizeof( yes );
};
template < typename T >
struct is_function_pointer {
static bool const value =
is_pointer_type<T>::value
&&
( ! is_pointer_to_class<T>::value )
&&
supports_conversion_to_pointer< typename is_pointer_type<T>:
ointee_type
* >::value;
};
typedef int (*fct_ptr) ( int, int );
typedef int (fct)( int );
class X {
public:
operator X* ( void ) {
return ( this );
}
};
struct Y {};
#include <iostream>
#include <iomanip>
#define SHOW_BOOL(expr) \
std::cout << #expr << " = " << std::boolalpha << (expr) << '\n';
int main ( void ) {
SHOW_BOOL( is_function_pointer<Y>::value );
SHOW_BOOL( is_function_pointer<Y*>::value );
SHOW_BOOL( is_function_pointer<Y**>::value );
SHOW_BOOL( is_function_pointer<X>::value );
SHOW_BOOL( is_function_pointer<X*>::value );
SHOW_BOOL( is_function_pointer<X**>::value );
SHOW_BOOL( is_function_pointer<int>::value );
SHOW_BOOL( is_function_pointer<int*>::value );
SHOW_BOOL( is_function_pointer<int**>::value );
SHOW_BOOL( is_function_pointer<fct_ptr>::value );
SHOW_BOOL( is_function_pointer<fct_ptr*>::value );
SHOW_BOOL( is_function_pointer<fct_ptr**>::value );
SHOW_BOOL( is_function_pointer<fct>::value );
SHOW_BOOL( is_function_pointer<fct*>::value );
SHOW_BOOL( is_function_pointer<fct**>::value );
}