Могу ли я извлечь структуру или открытые члены класса, используя шаблон? - PullRequest
3 голосов
/ 25 февраля 2010

В принципе, у меня есть много различных типов структур, таких как:

typedef struct
{
    char memberA;
    int memberB;
    ...
} tStructA;

Можно ли использовать шаблон для получения / извлечения произвольного члена из структуры? В псевдокоде я ищу что-то вроде этого:

/*This is pseudocode!*/
template <typename STRUCT_TYPE, typename MEMBER_TYPE, membername NAME>
class cMemberExtractor
{
    public:
        MEMBER_TYPE
        extract(const STRUCT_TYPE* pStruct) const
        {
             return pStruct->NAME;
        }
};    

Идея состоит в том, чтобы использовать шаблон следующим образом:

/*somewhere*/
void
producer()
{
    //produce update
    tStructA* pUpdate=new tStructA;
    ...
    //send update to receivers
    emit(pUpdate);
}


/*elsewhere*/
void
consumer(const tStructA* pUpdate)
{
    //extract data
    int data=cMemberExtractor<tStructA,int,memberB>().extract(pUpdate);
    //process data
    ...
}

Спасибо за вашу помощь!

Ответы [ 3 ]

4 голосов
/ 25 февраля 2010

Вы можете сделать это не с именами, а с указателями членов:

template <typename C, typename M>
struct updater_t {
   typedef M C::*member_ptr_t;

   updater_t( member_ptr_t ptr, M const & new_value )
      : new_value( new_value ), ptr(ptr)
   {}
   updater_t( member_ptr_t ptr, C & original )
      : new_value( original.*ptr ), ptr(ptr)
   {}
   void operator()( C & obj ) {
      obj.*ptr = new_value;
   }
   M new_value;
   member_ptr_t ptr;
};
struct test {
   int value;
};
int main() {
   updater_t<test,int> update( &test::value, 10 );
   test object;
   update( object );

   test object2;
   updater_t<test,int> update_copy( &test::value, object );
   update_copy( object2 );
}

Редактировать : перемещение указателя члена на аргумент шаблона, как указано в litb:

template <typename C, typename M, M C::* Ptr>
struct updater_t {
   updater_t( M const & new_value ) : new_value( new_value ) {}
   updater_t( member_ptr_t ptr, C & original ) : new_value( original.*Ptr ) {}
   void operator()( C & obj ) {
      obj.*ptr = new_value;
   }
   M new_value;
};
int main() {
   updater_t<test,int, &test::value> update( 10 );
   test object;
   update( object );
}
2 голосов
/ 25 февраля 2010

Это работает для меня:

#include <iostream>

struct Foo {
    int member;
    Foo() : member() {}
};

template< typename T, typename C >
T& extract(C& obj, T C::* member)
{
    return (obj.*member);
}

int main()
{
    Foo foo;
    std::cout << foo.member << '\n';
    extract(foo, &Foo::member) = 42;
    std::cout << foo.member << '\n';
    return 0;
}

extract(Object, &Class::Member) возвращает ссылку на Member в Object. Это то, что вы хотели?

0 голосов
/ 25 февраля 2010

Вам нужна помощь макросов.

#include <cstddef>

template <typename StructType, typename MemberType, size_t member_offset>
struct cMemberExtractor {
        MemberType extract(const StructType* pStruct) const {
             const char* member_loc = reinterpret_cast<const char*>(pStruct) + member_offset;
             return *(reinterpret_cast<const MemberType*>(member_loc));
        }
};

#define M_MEMBER_EXTRACTOR(STRU, MEMTYPE, MEMNAME) \
 (cMemberExtractor<STRU,MEMTYPE,offsetof(STRU,MEMNAME)>())
...

int data = M_MEMBER_EXTRACTOR(tStructA,int,memberB).extract(pUpdate);

Если ваш компилятор поддерживает оператор typeof, аргумент MEMTYPE может быть исключен для обеспечения безопасности типа.

#define M_MEMBER_EXTRACTOR(STRU, MEMNAME) \
 (cMemberExtractor<STRU,typeof(((STRU*)0)->MEMNAME),offsetof(STRU,MEMNAME)>())
...

int data = M_MEMBER_EXTRACTOR(tStructA,memberB).extract(pUpdate);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...