Как я могу получить составляющие функции-члена по ее адресу? - PullRequest
1 голос
/ 12 ноября 2010

Можно ли получить составляющие функции-члена, такие как тип класса или тип возвращаемого значения, только по ее адресу (а не по типу функции-члена)?

Например, учитывая

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

мне нравится иметь

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

Кроме того, я знаю, что функция-член имеет сигнатуру типа R (C::*)(), т.е. без аргументов и без cv-квалификации.

Спасибо.

Ответы [ 6 ]

3 голосов
/ 12 ноября 2010

Вы можете зафиксировать тип в функции шаблона:

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

печатает "OK", чтобы вы могли поставить там чек is_same.Я действительно не уверен, что вопрос, хотя - очевидно, что здесь мы используем тип функции-члена для вывода аргумента шаблона.

Если вы как-то неверно reinterpret_castуказатель на функцию-член на что-то другое, чтобы отбросить его тип, тогда вы не сможете его восстановить.

Если вы преобразовали указатель на функцию-член в совместимый тип указателя на функцию-член, например R (B::*)() -> R (D::*)(), где B - базовый класс D, тогда я думаю, что вы можете использовать dynamic_cast, чтобы проверить, действительно ли это функция B в конце концов.Вы не можете восстановить тип таким способом, просто typeid указателя на функцию-член, потому что это операция во время выполнения.Типы действительно существуют только во время компиляции в C ++, поэтому нет способа «получить» динамический тип значения, независимо от того, является ли это значение указателем на функцию-член или чем-то еще.Компилятор либо знает это, либо нет, и если это так, то существуют различные хитрости шаблона для фактического использования составляющих этого типа.

2 голосов
/ 12 ноября 2010

Неа.Это часть того, что называется отражение во время выполнения и невозможно на таком низкоуровневом языке, как C ++.Вы не можете получить эти данные только по адресу.

Что бы вы ни делали, в C ++ вы, вероятно, сможете сделать это с помощью метода метапрограммирования, используя магию шаблонов или магию препроцессора.Например, библиотеки Boost полагаются на такой подход.

1 голос
/ 12 ноября 2010

В C ++ pre-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;

А затем разверните вышеприведенный список для получения максимально возможной арности.

0 голосов
/ 12 ноября 2010

Если по какой-то причине вы передаете указатель на функцию-член как простой тип, вы можете получить составные части примерно так: (Для этого требуется C ++ 0x, в текущем C ++ для поддержки произвольных массивов потребуется намного больше работы.)

#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);
}
0 голосов
/ 12 ноября 2010
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
}
0 голосов
/ 12 ноября 2010

Вы можете использовать перегрузку:

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


F(foo.bar());

Вы можете использовать функции шаблона и частичную специализацию для более общего решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...