Nous utilisons boost - donc utiliser cette librairie devrait être bon.Comment spécialiser une classe modélisée pour la classification de type de données?
Mais je ne suis jamais parvenu à créer un ensemble de modèles qui vous donne la bonne spécialisation pour toute une classe de types de données, par opposition à la spécialisation pour un seul type de données (que je sais faire)). Laissez-moi aller un exemple pour essayer de ramener cela à la terre. Je veux avoir un ensemble de classes qui peut être utilisé comme:
Initialized<T> t;
Où T est soit un type de base simple, un PODS, ou un tableau. Cela ne peut pas être une classe, car une classe devrait avoir son propre constructeur, et écraser sa mémoire brute est une idée terrible.
Initialisé devrait essentiellement memset (& t, 0, sizeof (t)); Il est plus facile de s'assurer que le code d'exécution n'est pas différent du code de débogage lorsqu'il traite des structures existantes. Initialisé où SDT = type de données simple, devrait simplement créer une structure qui encapsule le SDT sous-jacent et utilise les compilateurs t() pour générer le constructeur par défaut défini par le compilateur pour ce type (cela peut aussi bien être un memset) il semble plus élégant pour résultat simplement t()
est ici un coup de poignard à elle, en utilisant initialisés <> pour PODs, et initialisés <> pour SDT:.
// zeroed out PODS (not array)
// usage: Initialized<RECT> r;
template <typename T>
struct Initialized : public T
{
// ensure that we aren't trying to overwrite a non-trivial class
BOOST_STATIC_ASSERT((boost::is_POD<T>::value));
// publish our underlying data type
typedef T DataType;
// default (initialized) ctor
Initialized() { Reset(); }
// reset
void Reset() { Zero((T&)(*this)); }
// auto-conversion ctor
template <typename OtherType> Initialized(const OtherType & t) : T(t) { }
// auto-conversion assignment
template <typename OtherType> Initialized<DataType> & operator = (const OtherType & t) { *this = t; }
};
et pour SDT:
// Initialised for simple data types - results in compiler generated default ctor
template <typename T>
struct Initialised
{
// default valued construction
Initialised() : m_value() { }
// implicit valued construction (auto-conversion)
template <typename U> Initialised(const U & rhs) : m_value(rhs) { }
// assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T &() { return m_value; }
operator const T &() const { return m_value; }
// the data
T m_value;
};
Je me suis spécialisé Initialisé pour T *, pour fournir des comportements de pointeurs naturels. Et j'ai un InitializedArray <> pour les tableaux, qui prend à la fois le type d'élément et la taille de tableau comme arguments de modèle. Mais encore une fois, je dois utiliser le nom du template pour le distinguer - je n'incrémente pas assez MPL pour fournir un template unique qui résulte de la spécialisation correcte à la compilation à partir d'un seul nom (Initialized <>, idéalement).
J'aimerais aussi être en mesure de fournir une surcharge Initialisé < typename T, T init_value > ainsi, de sorte que pour les valeurs non scalaires, l'utilisateur peut définir la valeur d'initialisation par défaut (ou valeur memset)
Je m'excuse d'avoir demandé quelque chose qui demande un peu d'effort pour répondre. Cela semble être un obstacle que je n'ai pas réussi à surmonter seul dans ma propre lecture MPL, mais peut-être qu'avec votre aide, je pourrais peut-être réduire cette fonctionnalité à plus tard!
Sur la base de la réponse de l'oncle Ben (s) ci-dessous, j'ai essayé les éléments suivants:
// containment implementation
template <typename T, bool bIsInheritable = false>
struct InitializedImpl
{
// publish our underlying data type
typedef T DataType;
// auto-zero construction
InitializedImpl() : m_value() { }
// auto-conversion constructor
template <typename U> InitializedImpl(const U & rhs) : m_value(rhs) { }
// auto-conversion assignment
template <typename U> T & operator = (const U & rhs) { if ((void*)&m_value != (void*)&rhs) m_value = rhs; return *this; }
// implicit conversion to the underlying type
operator T &() { return m_value; }
operator const T &() const { return m_value; }
// the data
T m_value;
};
// inheritance implementation
template <typename T>
struct InitializedImpl<T,true> : public T
{
// publish our underlying data type
typedef T DataType;
// auto-zero ctor
InitializedImpl() : T() { }
// auto-conversion ctor
template <typename OtherType> InitializedImpl(const OtherType & t) : T(t) { }
// auto-conversion assignment
template <typename OtherType> InitializedImpl<DataType> & operator = (const OtherType & t) { *this = t; }
};
// attempt to use type-traits to select the correct implementation for T
template <typename T>
struct Initialized : public InitializedImpl<T, boost::is_class<T>::value>
{
// publish our underlying data type
typedef T DataType;
};
Et puis essayé quelques tests d'utilisation.
int main()
{
Initialized<int> i;
ASSERT(i == 0);
i = 9; // <- ERROR
}
Il en résulte une erreur: * binaire '=': aucun opérateur trouvé qui prend un opérande à droite de type 'InitializedImpl ' (ou il n'y a pas de conversion acceptable)
Alors que si J'instancier directement le type de base correcte (au lieu d'un type dérivé):
int main()
{
InitializedImpl<int,false> i;
ASSERT(i == 0);
i = 9; // <- OK
}
maintenant, je peux-je utiliser comme tout ancien int. C'est ce que je veux!
exactement les mêmes problèmes se posent si j'essaie de faire la même chose pour struct:
int main()
{
Initialized<RECT> r;
ASSERT(r.left == 0); // <- it does let me access r's members correctly! :)
RECT r1;
r = r1; // <- ERROR
InitializedImpl<RECT,true> r2;
r2 = r1; // OK
}
Donc, comme vous pouvez le voir, il me faut une certaine façon de dire au compilateur de promouvoir un initialisées à agir comme un vrai T.
Si C++ me laisse hériter des types de base, je pourrais juste utiliser la technique d'héritage et tout irait bien.
Ou si j'avais un moyen de dire au compilateur d'extrapoler toutes les méthodes de parent à enfant, afin que tout ce qui était valide sur parent soit valide sur l'enfant, ça irait. Ou si je pouvais utiliser MPL ou des caractères de type pour typedef au lieu d'hériter de ce dont j'avais besoin, alors il n'y aurait pas de classe enfant, et pas de problème de propagation.
Idées! ...
Avec trop peu de temps pour avoir un réel Regardez-y: il semble que la spécialisation partielle, peut-être avec l'une ou l'autre utilisation 'boost :: enable_if', devrait faire ce que vous voulez. – gimpf