venant d'un arrière-plan principalement python, j'ai eu un peu de mal à travailler avec des types en C ++.
J'essaie d'initialiser une variable de classe via l'un des constructeurs surchargés qui prennent différents types comme paramètres. J'ai lu que l'utilisation du auto
mot - clé peut être utilisée pour la déclaration automatique d'une variable, mais dans mon cas, elle ne sera pas initialisée tant qu'un constructeur n'aura pas été choisi. Cependant, le compilateur n'est pas content de ne pas s'initialiser value
.
class Token {
public:
auto value;
Token(int ivalue) {
value = ivalue;
}
Token(float fvalue) {
value = fvalue;
}
Token(std::string svalue) {
value = svalue;
}
void printValue() {
std::cout << "The token value is: " << value << std::endl;
}
};
En python, cela pourrait ressembler à:
class Token():
def __init__(self, value):
self.value = value
def printValue(self):
print("The token value is: %s" % self.value)
Quelle est la bonne façon d'utiliser le auto
mot - clé dans ce scénario? Dois-je utiliser une approche complètement différente?
auto
pour les membres de la classe? Question pertinente mais obsolète: est-il possible d'avoir une variable membre «auto»?Réponses:
Il n'existe pas de "variable de type inconnu" en C ++.
Les variables déduites automatiquement ont un type qui est déduit de l'initialiseur. S'il n'y a pas d'initialiseur, vous ne pouvez pas utiliser auto. auto ne peut pas être utilisé pour une variable membre non statique. Une instance d'une classe ne peut pas avoir des membres de type différent d'une autre instance.
Il n'y a aucun moyen d'utiliser le mot-clé auto dans ce scénario.
Probablement. Il semble que vous essayiez d'implémenter un
std::variant
. Si vous avez besoin d'une variable pour stocker l'un des X types de types, c'est ce que vous devez utiliser.Cependant, vous essayez peut-être d'émuler la saisie dynamique en C ++. Bien que cela vous soit familier en raison de votre expérience avec Python, dans de nombreux cas, ce n'est pas l'approche idéale. Par exemple, dans cet exemple de programme particulier, tout ce que vous faites avec la variable membre est de l'imprimer. Il serait donc plus simple de stocker une chaîne dans chaque cas. D'autres approches sont le polymorphisme statique tel que montré par Rhathin ou le polymorphisme dynamique de style OOP comme montré par Fire Lancer.
la source
union
est un mécanisme de bas niveau sujet aux erreurs.variant
l'utilise probablement en interne et rend son utilisation plus sûre.variant
t utilisationunion
. L'alternative, utilisant la mémoire brute et le placement new, ne peut pas être utilisée dans unconstexpr
constructeur.C ++ est un langage typé statiquement , ce qui signifie que tous les types de variables sont déterminés avant l'exécution. Par conséquent,
auto
mot-clé n'est pas quelque chose commevar
mot-clé en javascript, qui est un langage typé dynamiquement.auto
Le mot-clé est couramment utilisé pour spécifier des types qui sont inutilement complexes.Ce que vous recherchez peut être fait à l'aide de la classe de modèle C ++ à la place, ce qui permet de créer plusieurs versions de la classe qui prennent différents types.
Ce code pourrait être la réponse que vous cherchez.
Ce code se compilerait si certaines conditions sont remplies, comme la fonction
operator<<
devrait être définie pour std :: ostream & et type T.la source
Une approche différente de celle que d'autres ont proposée consiste à utiliser des modèles. Voici un exemple:
Ensuite, vous pouvez utiliser votre classe comme ceci:
la source
Vous pouvez utiliser le
std::variant
type. Le code ci-dessous montre une façon (mais c'est un peu maladroit, je dois admettre):Il serait bien plus agréable d'
std::get<0>(value)
écrire lestd::get<value.index()>(value)
mais, hélas, le "x"<x>
doit être une expression constante au moment de la compilation.la source
std::visit
place deswitch
.auto
doit être déductible à un type spécifique, il ne fournit pas de typage dynamique à l'exécution.Si au moment de la déclaration,
Token
vous connaissez tous les types possibles que vous pouvez utiliser,std::variant<Type1, Type2, Type3>
etc. Cela revient à avoir un "type enum" et une "union". Il s'assure que les constructeurs et destructeurs appropriés sont appelés.Une alternative pourrait être de créer un
Token
sous-type différent pour chaque cas (en utilisant éventuellement des modèles) avec des méthodes virtuelles appropriées.la source
La solution ci-dessous est similaire dans son esprit à celle de la réponse de Fire Lancer. Sa principale différence est qu'il suit le commentaire en utilisant éventuellement des modèles , et supprime ainsi la nécessité de créer explicitement des instances dérivées de l'interface.
Token
n'est pas lui-même la classe d'interface. Au lieu de cela, il définit l'interface comme une classe interne et une classe de modèle interne pour automatiser la définition des classes dérivées.Sa définition semble trop complexe. Cependant,
Token::Base
définit l'interface etToken::Impl<>
dérive de l'interface. Ces classes internes sont entièrement cachées à l'utilisateur deToken
. L'utilisation ressemblerait à:De plus, la solution ci-dessous illustre comment on pourrait implémenter un opérateur de conversion pour affecter une
Token
instance à une variable régulière. Il s'appuie surdynamic_cast
, et lèvera une exception si le cast n'est pas valide.La définition de
Token
est ci-dessous.Essayez-le en ligne!
la source