Reputation: 73
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
Reputation: 208466
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
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
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