2010-03-04 2 views
2

: Pouvez-vous:Opérateur gabarit [] ... possible? Utile?

template <class T> 
const T &operator[] (unsigned int x) 

Ma pensée était si vous avez un map<string,string> il serait agréable d'avoir une classe wrapper qui vous permet de faire:

obj["IntVal"]="12"; 
obj["StringVal"]="Test"; 

int i = obj["IntVal"]; 

Comment près de ce qui peut nous réellement obtenir en C++? Cela vaut-il la peine?

+2

Les fonctions surchargées ne peuvent différer que par le type de retour. Donc ce ne serait pas simple, je pense. –

+2

Pour ce que ça vaut, j'ai déjà fait quelque chose comme ça et fini avec une syntaxe comme 'int i = obj [" IntVal "]. Comme ()'. Ou peut-être 'int i = obj.get (" IntVal ")'. Vous pourriez utiliser des conversions implicites pour obtenir la syntaxe que vous souhaitez, mais cela ouvrira d'autres mondes de douleur. –

+0

Une autre suggestion pour une syntaxe (que j'ai utilisée auparavant et qui est aussi utilisée dans pqxx) est de retourner la valeur en paramètre et de permettre au compilateur de faire type deduction: 'obj [clé] .to (var)'. Cela supprime le besoin du type explicite dans l'appel de la méthode. –

Répondre

4

Vous ne pouvez pas - dans:

int i = obj["IntVal"]; 

le type réel de T ne peut pas être déduit du contexte puisque le type de retour ne fait pas partie de la signature de la fonction.

De plus, le stockage des valeurs entières comme des chaînes ne sont pas considérées comme les meilleures pratiques, en raison de la mémoire et des considérations de performance ;-)

+0

@Seb Une bonne réponse, que j'espère avoir améliorée avec mon edit. Si non, n'hésitez pas à le faire rouler. –

+0

Vous avez fait :-) En tant que nouveau venu, je ne savais pas que vous pouviez utiliser le formatage de texte enrichi, désolé – Seb

+0

Pas besoin de vous excuser - pour formater le code, sélectionnez-le puis utilisez le bouton 1010 au-dessus de la zone de saisie de texte. N'essayez pas d'utiliser des balises HTML. –

0

Eh bien, ce que vous avez écrit dans votre exemple de code ne correspond pas à la question. En ce moment, vous avez seulement le type de retour basé sur un modèle.

Mais si vous voulez faire quelque chose comme:

template <class T> 
const T &operator[const T& x] 

qui est valide, mais peut-être pas très utile.

2

Ça ne vaut pas le coup. La modélisation du type de retour signifie que vous devez spécifier explicitement le paramètre du modèle lorsque vous l'appelez. Quelque chose comme ça, j'ai peut-être la mauvaise syntaxe:

int i = obj.operator[]<int>("IntVal"); 

C++ ne déduit pas les paramètres de modèle de ce que vous attribuez le résultat de l'appel, uniquement à partir des paramètres que vous appelez la fonction avec.

Alors vous pourriez aussi bien définir simplement une fonction normale:

int i = obj.get<int>("IntVal"); 

Ou dans ce cas, que ce soit faire ou mettre en œuvre get en utilisant ceci:

int i = boost:lexical_cast<int>(obj["IntVal"]); 

Comme le dit Amit, vous pouvez définir operator[] pour renvoyer un type qui peut être converti en int ou en d'autres types. Ensuite, votre code d'exemple peut être fait pour compiler sans lexical_cast explicite.

0

Une carte fournit déjà un operator[] surchargé qui fait la plupart de ce que vous voulez. La chose que vous semblez vouloir manquer est la conversion implicite d'une chaîne qui contient des chiffres en un entier. L'une des caractéristiques fondamentales de C++ est le typage statique, qui dit que cela ne devrait pas être autorisé - alors ce n'est pas le cas. Ce sera heureux de faire cette conversion si vous voulez, mais vous devrez le demander:

int i = lexical_cast<int>(obj["IntVal"]); 

Sinon, vous pouvez créer une classe de type corde qui a soutenu la conversion implicite à int. Personnellement, je déconseille cela.Je ne m'oppose pas aux conversions implicites aussi fortement que beaucoup de gens, mais cela me semble encore une idée assez moche, au moins pour une utilisation plus générale.

5

Vous pouvez également faire

class Class { 
    struct Proxy { 
    template<typename T> T as() { ... } 
    template<typename T> operator T() { return as<T>(); } 
    private: 
    Proxy(...) { ... } 
    Proxy(Proxy const&); // noncopyable 
    Proxy &operator=(Proxy const&); 
    friend class Class; 
    }; 

public: 
    Proxy operator[](std::string const& s) { ... } 
}; 

Class a; 
int i = a["foo"]; 
int i = a["foo"].as<int>(); 

T sera déduit à ce que l'être l'objet initialisé est. Et vous n'êtes pas autorisé à copier le proxy. Cela dit, je préfère une fonction explicite as<T> comme une autre proposée aussi.

+0

L'utilisation de 'operator []' ne semble pas possible avec cette méthode. Y a-t-il un moyen de faire fonctionner cela? – Max