我可以使用模板提取结构或公共类成员吗?

时间:2010-02-25 08:46:20

标签: c++ templates struct

基本上,我有很多不同类型的结构:

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 个答案:

答案 0 :(得分:4)

您可以使用名称但使用成员指针来执行此操作:

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

答案 1 :(得分:2)

这对我有用:

#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的引用。那是你想要的吗?

答案 2 :(得分:-1)

您需要宏的帮助。

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