2009-02-12 7 views
2

Je cherche à ajouter des fonctionnalités à tous les types simples en C++. Je souhaite écrire une seule classe basée sur un modèle qui prend comme paramètre modèle le type à encapsuler et dont tous les opérateurs sont définis de sorte que la classe encapsulée fonctionne exactement comme le type simple qu'elle encapsule.Encapsuler un type simple en utilisant des modèles C++

Quelque chose comme ceci:

template <typename _SimpleType_> 
class Attribute 
{ 
public: 
    Attribute(_SimpleType_ value){ m_value = value; } 
    ~Attribute(){} 

    // Cast 
    operator _SimpleType_() { return(m_value); } 

    // Comparisons 
    bool operator==(const a& other) const { return a == m_value; } 
    etc... 

private: 
    _SimpleType_ m_value; 
} 

// Use like: 
Attribute<int> i = 20; 

while(i) 
{ 
    if((i & 0xF) == 0) 
    { 
     i >>= 2; 
    } 

    i--; 
} etc... 

La question est que je suis sûr qu'il ya une charge de nuances qui doivent être traitées et les opérateurs de modèles spécialisés écrits; Y a-t-il un endroit où cela a déjà été fait pour que je puisse l'utiliser à la place? Boost est trop grand et compliqué à mettre dans mon projet mais je peux le regarder pour des pointeurs s'il y a une classe comme ça là dedans - quel est son nom s'il y en a?

+0

Notez que vous ne pouvez utiliser que les parties de boost dont vous avez réellement besoin. Si vous avez seulement besoin de shared_ptr, ajoutez seulement shared_ptr.hpp à votre projet. La plupart des bibliothèques sont uniquement des fichiers d'en-tête, vous n'avez donc pas besoin d'ajouter quoi que ce soit à votre processus de construction. – mch

Répondre

4

C'est assez simple, si fastidieux, - il suffit d'implémenter tous les opérateurs supportés par les types standards et où l'opérateur de cast n'est pas suffisant.

Je dois demander cependant, pourquoi diable essayez-vous de faire cela?

+0

Deuxièmement, pourquoi diable !? – mch

+1

Une bonne raison serait que le constructeur par défaut construise correctement le type contenu. Donc plus de variables non initialisées. –

+0

Ce n'est pas une bonne raison IMO! –

0

Je ne sais pas si boost::ref est ce que vous cherchez. Quoi qu'il en soit, la meilleure chose à faire est de simplement l'écrire à la main - mais cela commencera à devenir un problème si vous avez l'intention de prendre en charge la sémantique de pointeur et de référence. Ce que vous avez également besoin de faire est de le mettre dans un espace de noms et d'implémenter les surcharges de l'opérateur de fonction libre et de compter sur ADL pour qu'il soit récupéré. Cela deviendra un peu compliqué si vous implémentez de plus en plus d'opérateurs.

2

Vous pouvez obtenir l'implémentation des opérateurs non mutants gratuitement, juste par la conversion à _Simple_type_ (et vous obtiendriez les affectations et incrémenter/décrémenter par conversion à _Simple_type_&). Une autre question est de savoir si c'est vraiment une bonne idée, car il crée des conversions T à Attribute<T> et Attribute<T> à T ce qui provoque des problèmes lors de la surcharge - mais vous pouvez résoudre ce problème en rendant le constructeur de Attribute<T> explicite. Cela laisse les affectations et incrémenter/décrémenter - vous auriez juste à les implémenter.

Une autre possibilité consiste à utiliser boost::operators - une bibliothèque d'en-tête qui facilite la création de surcharges d'opérateur basées sur des règles algébriques. par exemple. vous créez operator+= et il vous fournira operator+. Vous créez operator< et operator== et il vous donnera les autres relationals etc.

1

ne pas faire avec votre question, mais vous devez savoir que des noms tels que _SimpleType_ (qui est, les noms qui commencent par un trait de soulignement et un caractère majuscule) sont réservés pour le compilateur C++ et les implémenteurs Standard Libarary à utiliser - vous n'êtes pas autorisé à les utiliser dans votre propre code.

2

Voici un exemple de faire avec un transtypage automatique à T & (testé avec GNU C++ 4.3.2):

#include <iostream> 

using namespace std; 

template <typename T> 
class Attribute { 
public: 
    Attribute(const T &value) { v = value; } 
    operator T &() { return v; } 
private: 
    T v; 
}; 

int main(int argc, char **argv) 
{ 
    Attribute<int> i(0); 
    i = 3; 
    i++; 
    i += 4; 
    i = i + 5; 
    i <<= 3; 
    cout << "i is now " << i << endl; 
} 

compilateur ++ Le C jette automagically la référence à 'Attribut' à une référence à 'int' en utilisant l'opérateur de la contrainte 'opérateur T &()'. Ainsi, lorsque la classe Attribute ne fournit pas l'opérateur '++' ou quoi que ce soit, l'objet est classé en int & puis l'opérateur est recherché à partir de là. N'hésitez pas à expérimenter.

0

J'aime cette forme d'encapsulation des types simples (auteur original - Sektor van Skijlen):

template<typename T> 
class explicit_t 
{ 
private: 
    T value; 

    template<typename V> explicit_t(V t); 
public: 
    operator T&() {return value;} 
    explicit_t(const T& c) : value(c) {}  
}; 

et le court exemple:

void fun(explicit_t<int> foo) {} 

int main() 
{ 
     // fun('a'); 
     // fun(3u); 
     // fun(3.0); 
     fun(4); 
} 

Alors que dois-je obtenir? Plus de conversions indésirables. Vous pouvez également regarder quelque chose de plus sophistiqué - typegen.

Questions connexes