如何从其地址获取成员函数的成员?

时间:2010-11-12 16:00:49

标签: c++ templates

是否可以从其地址(不是来自成员函数类型)获取成员函数(例如类类型或返回类型)的组成部分?

例如给出

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

我喜欢

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

我还知道成员函数有一个像R (C::*)()这样的签名,即没有参数,也没有cv资格。

谢谢。

6 个答案:

答案 0 :(得分:3)

您可以在模板函数中捕获类型:

#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);
}

打印“确定”,这样您就可以将is_same支票放入其中。我真的不确定问题是什么 - 显然我们 使用成员函数的类型进行模板参数推导。

如果你以某种方式无效地reinterpret_cast成员函数指向别的东西,以便丢弃它的类型,那么你就无法恢复它。

如果您已将成员函数指针转换为兼容的成员函数指针类型,例如R (B::*)() - &gt; R (D::*)(),其中B是D的基类,那么我认为你可以使用dynamic_cast来测试它是否真的是一个B函数。您无法以这种方式恢复类型,只能恢复成员函数指针的typeid,因为它是运行时操作。类型实际上只存在于C ++的编译时,因此没有办法“获取”值的动态类型,无论该值是成员函数指针还是其他任何值。编译器要么知道它,要么不知道,如果确实如此,那么实际上使用该类型的组成部分会有各种模板技巧。

答案 1 :(得分:2)

不。这是所谓的运行时反射的一部分,在C ++这样的低级语言中是不可能的。您无法仅从地址获取此数据。

无论你在做什么,在C ++中你都可以使用元编程方法,使用模板魔法或预处理器魔法来做到这一点。例如,Boost库依赖于这种方法。

答案 2 :(得分:1)

在C ++之前的0x中,你不能很容易地做到这一点。在C ++ 0x中,您可以使用模板函数和decltype的组合来执行此操作:

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;

然后根据需要将上述内容扩展为高度优化。

答案 3 :(得分:0)

您可以使用重载:

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


F(foo.bar());

您可以使用模板功能和部分专业化来获得更通用的解决方案。

答案 4 :(得分:0)

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
}

答案 5 :(得分:0)

如果由于某种原因您将成员函数指针作为简单类型传递,则可以使用以下内容获取组成部分。 (这需要C ++ 0x,在当前的C ++中,它支持任意arities将需要更多的工作。)

#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);
}