determine if a type is a free function pointer

F

Fei Liu

I am trying to experiment with typetraits such that I can determine if a
type is a free function pointer type. The following code example works
but it's not generic. As you can see, I have to enumerate the function
signatures. Is there a generic solution? (... doesn't work btw).

Fei

#include <iostream>

using namespace std;

template <typename T>
class typetraits{
template <typename U>
struct is_free_func_ptr {
enum { result = false };
};

template <typename U>
struct is_free_func_ptr<U (*)()>{
enum { result = true };
};

template <typename U, typename V>
struct is_free_func_ptr<U (*)(V)>{
enum { result = true };
};

public:
enum { result = is_free_func_ptr<T>::result };
};

void foo() { }
void foo(int) { }

struct f{
void operator ()() const {}
};

int main(){
typedef void (*foo_fp)();
typedef int (*foo_fp2)(int);
cout << "result: " << typetraits<foo_fp>::result << endl;
cout << "result: " << typetraits<foo_fp2>::result << endl;
cout << "result: " << typetraits<void *>::result << endl;
cout << "result: " << typetraits<void>::result << endl;
cout << "result: " << typetraits<f>::result << endl;
}
 
V

Victor Bazarov

Fei said:
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?
The following code
example works but it's not generic. As you can see, I have to
enumerate the function signatures. Is there a generic solution? (...
doesn't work btw).
Fei

#include <iostream>

using namespace std;

template <typename T>
class typetraits{
template <typename U>
struct is_free_func_ptr {
enum { result = false };
};

template <typename U>
struct is_free_func_ptr<U (*)()>{
enum { result = true };
};

template <typename U, typename V>
struct is_free_func_ptr<U (*)(V)>{
enum { result = true };
};

public:
enum { result = is_free_func_ptr<T>::result };
};

void foo() { }
void foo(int) { }

struct f{
void operator ()() const {}
};

int main(){
typedef void (*foo_fp)();
typedef int (*foo_fp2)(int);
cout << "result: " << typetraits<foo_fp>::result << endl;
cout << "result: " << typetraits<foo_fp2>::result << endl;
cout << "result: " << typetraits<void *>::result << endl;
cout << "result: " << typetraits<void>::result << endl;
cout << "result: " << typetraits<f>::result << endl;
}

What output do you expect?

V
 
F

Fei Liu

Victor said:
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.
What output do you expect?

in this case the code works fine. 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.

#include <iostream>

using namespace std;

template <typename T>
class typetraits{
template <typename U>
struct is_free_func_ptr {
enum { result = false };
};

template <typename U>
struct is_free_func_ptr<U (*)()>{
enum { result = true };
};

template <typename U, typename V>
struct is_free_func_ptr<U (*)(V)>{
enum { result = true };
};

public:
enum { result = is_free_func_ptr<T>::result };
};

void foo() { }
void foo(int) { }
void foo(int,int) { }

struct f{
void operator ()() const {}
};

int main(){
typedef void (*foo_fp)();
typedef int (*foo_fp2)(int);
typedef int (*foo_fp3)(int,int);
cout << "result: " << typetraits<foo_fp>::result << endl;
cout << "result: " << typetraits<foo_fp2>::result << endl;
cout << "result: " << typetraits<foo_fp3>::result << endl;
cout << "result: " << typetraits<void *>::result << endl;
cout << "result: " << typetraits<void>::result << endl;
cout << "result: " << typetraits<f>::result << endl;
}
 
V

Victor Bazarov

Fei said:
Victor said:
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...

V
 
B

Barry

Fei said:
I am trying to experiment with typetraits such that I can determine if a
type is a free function pointer type. The following code example works
but it's not generic. As you can see, I have to enumerate the function
signatures. Is there a generic solution? (... doesn't work btw).

Fei

#include <iostream>

using namespace std;

template <typename T>
class typetraits{
template <typename U>
struct is_free_func_ptr {
enum { result = false };
};

template <typename U>
struct is_free_func_ptr<U (*)()>{
enum { result = true };
};

template <typename U, typename V>
struct is_free_func_ptr<U (*)(V)>{
enum { result = true };
};

public:
enum { result = is_free_func_ptr<T>::result };
};

void foo() { }
void foo(int) { }

struct f{
void operator ()() const {}
};

int main(){
typedef void (*foo_fp)();
typedef int (*foo_fp2)(int);
cout << "result: " << typetraits<foo_fp>::result << endl;
cout << "result: " << typetraits<foo_fp2>::result << endl;
cout << "result: " << typetraits<void *>::result << endl;
cout << "result: " << typetraits<void>::result << endl;
cout << "result: " << typetraits<f>::result << endl;
}

Well
tr1 has is_function, I didn't carefully checked out how Boost.TypeTraits
implements it,

But I think life can be much easier if we have variadic template
parameter language support
 
K

Kai-Uwe Bux

Victor said:
Fei said:
Victor said:
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 );
}


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Kai-Uwe Bux said:
Victor said:
Fei said:
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>::pointee_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 );
}


Best

Kai-Uwe Bux
 
B

Barry

Kai-Uwe Bux said:
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>::pointee_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 );
}

Good job,

boost.is_function seems to do hard coding to meet possible function
argument list length.

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 );
 
K

Kai-Uwe Bux

Barry said:
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 ) );

};


// is_function_pointer
// ===================

template < typename T >
struct is_function_pointer {

static bool const value =
( is_pointer_type<T>::value
&&
is_function_type< typename is_pointer_type<T>::pointee_type >::value );

};


Note that the template is_function_type<> does not need the
is_pointer_type<> template. That is why I think that is_function_type<> is
conceptually simpler than is_function_pointer<> and my reason to prefer
this implementation to the previous one.


Best

Kai-Uwe Bux
 
B

Barry

Kai-Uwe Bux said:
Barry wrote:
Note that the template is_function_type<> does not need the
is_pointer_type<> template. That is why I think that is_function_type<> is
conceptually simpler than is_function_pointer<> and my reason to prefer
this implementation to the previous one.

So
int (int) is convertible to int (*)(int), which is the basis of your
implementation.

where does the standard mention this?
 
K

Kai-Uwe Bux

Barry said:
So
int (int) is convertible to int (*)(int), which is the basis of your
implementation.

where does the standard mention this?

Clause [4.3/1]

4.3 Function-to-pointer conversion [conv.func]

1 An lvalue of function type T can be converted to an rvalue of
type ?pointer to T.? The result is a pointer to the function.


Best

Kai-Uwe Bux
 
F

Fei Liu

Kai-Uwe Bux said:
Barry said:
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 ) );

};


// is_function_pointer
// ===================

template < typename T >
struct is_function_pointer {

static bool const value =
( is_pointer_type<T>::value
&&
is_function_type< typename is_pointer_type<T>::pointee_type >::value );

};


Note that the template is_function_type<> does not need the
is_pointer_type<> template. That is why I think that is_function_type<> is
conceptually simpler than is_function_pointer<> and my reason to prefer
this implementation to the previous one.


Best

Kai-Uwe Bux

Hmm...are you positive that your implemention meets my requirement?
There are 2 problems after I test run your typetraits implementation:

! is_pointer_type<int>::value = true
is_pointer_type<non_fct_ptr>::value = true
is_pointer_type<fct_ptr>::value = true
is_function_pointer<fct_ptr>::value = true
! is_function_pointer<non_fct_ptr>::value = true <----------- wrong
! is_function_pointer<fct_ptr4>::value = false <----------- wrong


// 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 ) );

};


// is_function_pointer
// ===================

template < typename T >
struct is_function_pointer {

static bool const value =
( is_pointer_type<T>::value
&&
is_function_type said:
>::value );

};

typedef int (*fct_ptr) ( int, int );
typedef int * non_fct_ptr;
typedef void (*fct_ptr4)(int, int, int, int);


#include <iostream>
#include <iomanip>

#define SHOW_BOOL(expr) \
std::cout << #expr << " = " << std::boolalpha << (expr) << '\n';

int main ( void ) {
SHOW_BOOL( ! is_pointer_type<int>::value );
SHOW_BOOL( is_pointer_type<non_fct_ptr>::value );
SHOW_BOOL( is_pointer_type<fct_ptr>::value );
SHOW_BOOL( is_function_pointer<fct_ptr>::value );
SHOW_BOOL( ! is_function_pointer<non_fct_ptr>::value );
SHOW_BOOL( ! is_function_pointer<fct_ptr4>::value );
}
 
F

Fei Liu

Fei said:
Kai-Uwe Bux said:
Barry said:
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 ) );
};

// is_function_pointer
// ===================
template < typename T >
struct is_function_pointer {
static bool const value =
( is_pointer_type<T>::value
&&
is_function_type said:
::value );
};


Note that the template is_function_type<> does not need the
is_pointer_type<> template. That is why I think that
is_function_type<> is
conceptually simpler than is_function_pointer<> and my reason to prefer
this implementation to the previous one.


Best

Kai-Uwe Bux

Hmm...are you positive that your implemention meets my requirement?
There are 2 problems after I test run your typetraits implementation:

! is_pointer_type<int>::value = true
is_pointer_type<non_fct_ptr>::value = true
is_pointer_type<fct_ptr>::value = true
is_function_pointer<fct_ptr>::value = true
! is_function_pointer<non_fct_ptr>::value = true <----------- wrong
! is_function_pointer<fct_ptr4>::value = false <----------- wrong

I apologize, the result is indeed correct...I start to think the reason
my initial implementation didn't work was missing the implicit function
type to function pointer type conversion.

Thanks, this discussion is very helpful.
Fei
 
F

Fei Liu

Kai-Uwe Bux said:
Barry said:
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? Now I know why managers don't like C++.

Fei
 
K

Kai-Uwe Bux

Fei said:
Kai-Uwe Bux said:
Barry said:
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
 
F

Fei Liu

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

I am not very sure if fun is the word that would pop up in most people's
head when they see this piece of code, most likely explosion...
 
F

Fei Liu

Kai-Uwe Bux said:
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.
Are you positive this statement is correct? because the following
statements are perfect C++:
typedef int(*fp)(int);
fp func();
fp* func(int);
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.

check my first comment.
 
V

Victor Bazarov

Fei said:
Kai-Uwe Bux said:
[..] 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.
Are you positive this statement is correct? because the following
statements are perfect C++:
typedef int(*fp)(int);
fp func();
fp* func(int);

Where in those statements a function is the return type? 'fp' is
not a function it's a pointer to function. Pointers to functions
make perfect return types.

Now, here is the problem:

typedef int(*fp)(int); // fp is a pointer to a function

// here is a class template whose 'bar' returns
// the template argument:
template<class T> class foo { T bar(); };

// here is a specialisation for "pointers", notice that
// the 'bar' returns the "pointed-to" type
template<class T> class foo<T*> { T bar(); };

int main() {
foo<fp> f;
f.bar(); // KABOOM: function returning function
}

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top