conversions implicites ne sont pas considérés comme des objets d'appels de fonctions membres, y compris la surcharge de l'opérateur de l'indice. Considérez les conséquences si cela était autorisé: Chaque fois qu'une fonction membre non déclarée est appelée comme ceci, le compilateur devrait comprendre tous les types auxquels l'objet peut être converti (notez que tout autre type non apparenté pourrait avoir un constructeur de conversion), et vérifier si cela a déclaré la fonction membre manquant. Sans parler de la confusion que cela pourrait avoir pour le lecteur du code (la conversion peut être évidente dans votre cas d'opérateur de conversion, mais pas dans le cas du constructeur de conversion, et pour autant que je sache, ils ne sont pas traités différemment).
Ainsi est-il un moyen notationally pratique d'obtenir Prop de se comporter de la façon dont je veux
Vous devez définir une fonction membre pour chacune des fonctions de membre du vecteur que vous voulez passer passe par transparence.Voici l'opérateur comme un exemple indice:
auto operator[](std::size_t pos) {
return value[pos];
}
auto operator[](std::size_t pos) const {
return value[pos];
}
Le problème est bien sûr que toutes les fonctions membres enveloppées doivent être explicitement déclarés. Un autre problème est les arguments dont le type dépend de T
. Par exemple, vector::operator[]
utilise vector::size_type
, qui peut ne pas être défini pour tous T
que vous pourriez utiliser (certainement pas pour float
). Ici nous faisons un compromis et utilisons std::size_t
.
Une manière moins laborieuse de créer une telle enveloppe "transparente" est l'héritage. Un modèle héritant publiquement aurait automatiquement toutes les fonctions membres du parent et serait implicitement convertible en celui-ci et pourrait être référé par des pointeurs et des références de type parent. Cependant, la transparence d'une telle approche est un peu problématique principalement parce que ~vector
n'est pas virtuel.
héritage privé permet même emballage que votre approche membre, mais avec une syntaxe beaucoup plus agréable:
template<typename T>
struct Prop : private T
{
using T::operator[];
using T::T;
};
Notez que l'approche de l'héritage vous empêche d'utiliser les types fondamentaux T
. En outre, il rend la conversion implicite impossible (même avec l'opérateur de conversion), donc vous ne pouvez pas utiliser Prop
comme T
dans les fonctions libres qui attendent T
.
PS. Notez que votre opérateur de conversion renvoie une valeur, donc le vecteur doit être copié, ce qui peut être indésirable. Envisager de fournir des versions de référence à la place:
operator T&&()&& { return *this; }
operator T&()& { return *this; }
operator const T&() const& { return *this; }
L'expression 'p2 [0]' est en fait la même chose que 'p2.operator [] (0)' (qui devrait être possible de déduire des messages d'erreur). Et la classe 'Prop' n'a pas de fonction' operator [] '. –
Donc le problème est que p2 [0] est considéré comme une expression, non? Parce que si p2 devait être considéré comme une expression en soi, la conversion en std :: vector serait effectuée, et alors .operator [] (0) serait appelé, non? Il existe donc un moyen pratique de faire en sorte que Prop se comporte comme je le souhaite, c'est-à-dire un conteneur transparent pour une valeur de type T, avec certains attributs (car dans mon code réel, Prop a des membres supplémentaires, bien sûr). – Roel
La manière habituelle d'encapsuler des données de ce type est de surcharger l'opérateur d'accès membre '->' ou l'opérateur de déréférencement '*'. Ensuite, vous pouvez faire quelque chose comme 'p2-> à (0)', ou '(* p2) [0]'. C'est plus encombrant, mais c'est quand même mieux qu'un static_cast. –