modèle de méta-programmation OU opération
Question
J'ai une classe qui peut être décorée avec un ensemble de modèles supplémentaires pour fournir des fonctionnalités supplémentaires. Chaque module complémentaire a une valeur d'identification addon que la classe de base doit connaître.
Le code ci-dessous est un exemple de ce que j'aimerais faire. De toute évidence, la fonction main () ne parvient pas à compiler. L'objectif est que CBase :: GetValueOfAddOns () connaisse la valeur de OR-ing la valeur addon_value pour chaque module complémentaire. Le calcul ne doit pas nécessairement être effectué dans GetValueOfAddOns (), il doit simplement être capable d’obtenir le résultat.
template< class T >
class AddOn_A : public T
{
public:
AddOn_A( int x ) : T( x )
{};
enum { addon_value = 0x00000001 };
};
template< class T >
class AddOn_B : public T
{
public:
AddOn_B( int x ) : T( x )
{};
enum { addon_value = 0x00000010 };
};
class CBase
{
public:
explicit CBase( int x ) : x_( x )
{
// error LNK2001: unresolved external symbol "public: virtual int __thiscall CBase::GetValueOfAddOns(void)const " (?GetValueOfAddOns@CBase@@UBEHXZ)
int z = GetValueOfAddOns();
};
virtual int GetValueOfAddOns() const = 0;
private:
int x_;
};
// define an empty AddOn
template< class > class empty
{
public:
enum { addon_value = 0x00000000 };
};
// forward declaration and Add-On defaults
template< template< class > class AddOn1 = empty,
template< class > class AddOn2 = empty,
template< class > class AddOn3 = empty >
class CMyClass;
// specialized template for the default case
template<> class CMyClass< empty, empty, empty > : public CBase
{
public:
CMyClass( int x ) : CBase( x )
{};
enum { addon_value = 0x00000000 };
};
// actual definition
template< template< class > class AddOn1,
template< class > class AddOn2,
template< class > class AddOn3 >
class CMyClass : public AddOn1< CBase >,
public CMyClass< AddOn2, AddOn3 >
{
public:
CMyClass( int x ) : AddOn1< CBase >( x ),
CMyClass< AddOn2, AddOn3 >( x )
{};
enum { addon_value = AddOn1< CBase >::addon_value | CMyClass< AddOn2, AddOn3 >::addon_value };
int GetValueOfAddOns() const
{
return addon_value;
}
};
int _tmain( int argc, _TCHAR* argv[] )
{
CMyClass< AddOn_A > A( 0 );
_ASSERT( A.GetValueOfAddOns() == AddOn_A< CBase >::addon_value );
CMyClass< AddOn_A, AddOn_B > AB( 0 );
_ASSERT( AB.GetValueOfAddOns() == ( AddOn_A< CBase >::addon_value | AddOn_B< CBase >::addon_value ) );
return 0;
}
Merci pour toute aide, PaulH
La solution
Je ne suis pas sûr que ce soit la manière la plus élégante, mais voici ce qui est assez simple:
Ajouter ceci à CMyClass:
enum {AddonsValues = AddOn1<CBase>::addon_value | CMyClass<AddOn2, AddOn3>::AddonsValues};
int GetValueOfAddOns()
{
// return the result of OR-ing the addon_value of each add-on.
return AddonsValues;
};
et ceci aux spécialistes CMyClass<empty, empty, empty>
:
enum {AddonsValues = 0};
Autres conseils
Si vous rendez cette fonction pure virtual
, vous pouvez l’implémenter dans CMyClass
, où vous avez toutes les informations disponibles. Changez simplement votre empty
classe pour définir enum { addon_value = 0x00000000 };
, ce qui facilitera les choses.
Améliorons les choses:
Consultez votre nouvelle question sur le problème de hiérarchie ici J'ai également résolu le problème AddOnValues, et la méta-programmation de modèles n'est pas nécessaire, vraiment.