2010-02-25 3 views
3

Fondamentalement, j'ai beaucoup de struct différemment typés comme ceci:Puis-je extraire des membres de la classe struct ou public à l'aide d'un modèle?

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

Est-il possible d'utiliser un modèle pour obtenir/extraire un membre arbitraire du struct? Dans pseudocode, je cherche quelque chose comme ceci:

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

L'idée est derrière d'utiliser le modèle comme celui-ci:

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

Merci pour votre aide!

+0

Je pense que non, parce que C++ n'a pas de vraies métadonnées d'objet à l'exécution, mais je pourrais ne pas être clair sur ce que vous demandez. Il pourrait également y avoir un hack préprocesseur horrible pour cela. –

+2

Quel est le problème avec 'int data = pUpdate-> memberB;'? – kennytm

+0

@Travis: Qui parlait de l'exécution? – sbi

Répondre

4

Vous pouvez le faire avec les noms mais avec des pointeurs membres:

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

Modifier: Déplacement du pointeur de membre à un argument de modèle tel que suggéré par 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); 
} 
+0

Oui, c'est exactement ce que je veux (cela m'a pris du temps car je n'avais pas encore vu de pointeurs de membres). .. merci beaucoup veeery! – Axel

+0

Notez que l'utilisation principale de ce type d'objet n'est pas en fait la syntaxe (ce qui rendra certains IDE étranglés lors de l'auto-complétion), mais plutôt qu'elle peut être utilisée comme une brique pour annuler une pile ou des modifications transactionnelles. –

+0

Il est effectivement possible de l'avoir plus performant et plus proche de l'utilisation désirée en mettant le pointeur membre dans le modèle comme le montre la question: 'template class updater_t {..} ". –

-1

Vous avez besoin d'aide des 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); 

Si votre compilateur prend en charge l'opérateur typeof, l'argument MEMTYPE peut être éliminé pour aider la sécurité de type.

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

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

@KennyTM: Thx pour votre message, mais je voudrais éviter #defines, dans la mesure du possible ... – Axel

2

Cela fonctionne pour moi:

#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) renvoie une référence à Member dans Object. Est-ce ce que tu voulais?

+0

Oui, c'est exactement ce que je voulais! Je vous remercie! (Sry, David a été plus rapide ...) – Axel

Questions connexes