Axel
Axel

Reputation: 73

Can I extract struct or public class members using a template?

Basically, I have lots of differently typed structs like this:

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

Is it possible to use a template to get/extract an arbitrary member from the struct? In pseudocode, I'm looking for something like this:

/*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;
        }
};    

The idea behind is to use the template like this:

/*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
    ...
}

Thanks for your help!

Upvotes: 3

Views: 1134

Answers (3)

You can do that not with names but with member pointers:

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

Edit: Moving the member pointer to a template argument as suggested by 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 );
}

Upvotes: 5

sbi
sbi

Reputation: 224199

This works for me:

#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) returns a reference to Member in Object. Is that what you wanted?

Upvotes: 2

kennytm
kennytm

Reputation: 523784

You need help from macros.

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

If your compiler supports the typeof operator, the MEMTYPE argument can be eliminated to help type safety.

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

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

Upvotes: -1

Related Questions