简体   繁体   中英

How can i get constituents of a member function from its address?

Is it possible to get the constituents of a member function such as class type or return type just from its address (not from member function type) ?

For eg given

 class foo
 {
    int bar()
    {
        return 5;
    }
 };

i like to have

is_same< function_types<&foo::bar>::class_type, foo>::value == true; 

I also know additionally that the member function has a signature like R (C::*)() ie no arguments and no cv-qualification.

Thank you.

You can capture the type in a template function:

#include <iostream>

struct foo {
    foo() { std::cout << "OK\n"; }
    int bar() {return 0;}
};

template<typename C, typename R>
bool thing(R (C::*)()) {
    C x;
}

int main() {
    thing(&foo::bar);
}

prints "OK", so you could put your is_same check in there. I'm really not sure what the question is, though - obviously here we are using the type of the member function for template argument deduction.

If you've somehow invalidly reinterpret_cast a member function pointer to something else, so as to discard its type, then no you can't recover it.

If you've converted your member function pointer to a compatible member function pointer type, for example R (B::*)() -> R (D::*)() , where B is a base class of D, then I think you can use dynamic_cast to test whether it really is a B function after all. You can't recover the type that way, just the typeid of the member function pointer, because it's a runtime operation. Types really only exist at compile-time in C++, so there's no way to "get" the dynamic type of a value, whether that value is a member function pointer or anything else. The compiler either knows it, or it doesn't, and if it does then there's various template trickery to actually use the constituents of that type.

Nope. This is part of what is called run-time reflection and is not possible in such low-level language as C++. You cannot get this data from only the address.

Whatever you're doing, in C++ you're likely to be able to do this with a metaprogramming approach, using template magic or preprocessor magic. For example, Boost libraries rely on such approach.

In C++ pre-0x, you can't do this very easily. In C++0x, you can use a combination of template functions and decltype to do this:

template <typename R> struct unary_function_info { typedef R result_type; typedef void class_type; };
template <typename R> unary_function_info get_function_info(R (*)());

template <typename C, typename R> struct unary_member_function_info { typedef R result_type; typedef C class_type; };
template <typename C, typename R> unary_member_function_info get_function_info(R (C::*)());

is_same<decltype(get_function_info(&foo::bar))::class_type, foo>::value == true;

And then expand the above out for as high an arity as you need.

You could use overloading:

void F(int);
void F(bool);


F(foo.bar());

You can use template functions and partial specialisation for a more generic solution.

struct char2_t { char xxx[2]; };

template <bool flag, typename T, typename U> struct select   { typedef T type; }; 
template <typename T, typename U> struct select<false, T, U> { typedef U type; }; 

template<class Foo, class C, class R>
typename select<boost::is_same<Foo, C>::value, char, char2_t>::type test(R (C::*)());


void check_in_this_function() {
 char check_arr1[ sizeof(test<foo>(&foo::bar))==1 ? 1 : -1]; 
 char check_arr2[ sizeof(test<int>(&foo::bar))==1 ? 1 : -1];  // error: negative subscript
}

If for some reason you are passing around a member function pointer as a simple type, you can get the constituent parts with something like the following. (This requires C++0x, in current C++ making it support arbitrary arities would take a lot more work.)

#include <tuple>

template <class T>
struct method_traits;

template <class ReturnType, class ObjectType, class... ArgTypes>
struct method_traits<ReturnType (ObjectType::*)(ArgTypes...)>
{
    typedef ReturnType result_type;
    typedef ObjectType object_type;
    template <unsigned N>
    struct argument
    {
        typedef typename std::tuple_element<N - 1, std::tuple<ArgTypes...>>::type type;
    };
};

template <class ReturnType, class ObjectType, class... ArgTypes>
struct method_traits<ReturnType (ObjectType::*)(ArgTypes...) const>
{
    typedef ReturnType result_type;
    typedef ObjectType object_type;
    template <unsigned N>
    struct argument
    {
        typedef typename std::tuple_element<N - 1, std::tuple<ArgTypes...>>::type type;
    };
};

struct Foo
{
    int bar(double, float) const ;
};

template <class MemberFun>
void test(MemberFun f)
{
    typename method_traits<MemberFun>::result_type result;
    typename method_traits<MemberFun>::object_type object;
    typename method_traits<MemberFun>::template argument<1>::type i = 10;  //:)
    result = (object.*f)(i, 2.0f);
}

int main()
{
    test(&Foo::bar);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM