std::any
a à mettre en œuvre avec l'effacement de type. C'est parce qu'il peut stocker cualquier et ne peut pas être un modèle. Il n'y a tout simplement aucune autre fonctionnalité en C++ pour réaliser cela pour le moment.
Ce que cela signifie, c'est que std::any
stockera un pointeur effacé par type, void*
y std::any_cast
va convertir ce pointeur au type spécifié et c'est tout. Il effectue juste un contrôle d'intégrité en utilisant typeid
avant de vérifier si le type sur lequel vous l'avez coulé est celui stocké dans le any.
Autoriser les conversions implicites serait impossible avec l'implémentation actuelle. Pensez-y (ignorez le typeid
vérifier pour l'instant).
std::any_cast<long>(a);
a
enregistre un int
et non un long
. Comment std::any
vous le savez ? Il peut juste lancer son void*
au type spécifié, le déréférencer et le retourner. Le transfert d'un pointeur d'un type à l'autre est une violation stricte de l'aliasing et donne lieu à un UB, c'est donc une mauvaise idée.
std::any
devrait stocker le type réel de l'objet qui y est stocké, ce qui n'est pas possible. On ne peut pas stocker les types en C++ pour le moment. Il pourrait maintenir une liste de types avec leurs noms respectifs. typeid
et passer de l'un à l'autre pour obtenir le type actuel et effectuer la conversion implicite. Mais il n'y a aucun moyen de faire cela pour cada le type unique que vous allez utiliser. Les types définis par l'utilisateur ne fonctionneraient pas de toute façon, et vous devriez compter sur des choses telles que les macros pour "enregistrer" votre type et générer le cas de commutation approprié pour celui-ci. 1 .
Peut-être quelque chose comme ça :
template<typename T>
T any_cast(const any &Any) {
const auto Typeid = Any.typeid();
if (Typeid == typeid(int))
return *static_cast<int *>(Any.ptr());
else if (Typeid == typeid(long))
return *static_cast<long *>(Any.ptr());
// and so on. Add your macro magic here.
// What should happen if a type is not registered?
}
Est-ce une bonne solution ? Non, et de loin. Le changement est coûteux, et le mantra de C++ est "vous ne payez pas pour ce que vous n'utilisez pas", donc non, il n'y a aucun moyen de réaliser cela actuellement. L'approche est également "hacky" et très fragile (que se passe-t-il si vous oubliez d'enregistrer un type). En bref, les avantages éventuels d'une telle approche ne valent pas la peine de s'y attarder.
Existe-t-il une solution de contournement pour permettre une conversion implicite (dans le cas où le type exact que std::any détient est inconnu) ?
Oui, mettre en œuvre std::any
(ou un type comparable) et std::any_cast
vous-même en utilisant l'approche du registre macro mentionnée ci-dessus 1 . Mais je ne le recommanderai pas. Si vous n'avez pas et ne pouvez pas savoir quel type std::any
et que vous devez y accéder, vous avez peut-être un défaut de conception.
1 : Je ne sais pas vraiment si c'est possible, je ne suis pas très doué pour l'(ab)utilisation des macros. Vous pouvez également coder en dur vos types pour votre implémentation personnalisée ou utiliser un outil séparé pour cela.
1 votes
Ce n'est ni possible ni nécessaire ! En effet, d'autres langues ont exactement la même restriction pour l'unboxing . Je ne peux pas penser à un seul scénario où cela serait problématique.