Le modèle que beaucoup de gens utilisent avec les variantes C++17 / boost ressemble beaucoup aux instructions switch. Par exemple : ( extrait de cppreference.com )
std::variant<int, long, double, std::string> v = ...;
std::visit(overloaded {
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
Le problème se pose lorsque l'on met le mauvais type dans le visiteur ou que l'on modifie la signature de la variante, mais que l'on oublie de modifier le visiteur. Au lieu d'obtenir une erreur de compilation, vous aurez le mauvais lambda appelé, généralement celui par défaut, ou vous pourriez obtenir une conversion implicite que vous n'avez pas prévue. Par exemple, vous pouvez obtenir une conversion implicite que vous n'avez pas prévue :
v = 2.2;
std::visit(overloaded {
[](auto arg) { std::cout << arg << ' '; },
[](float arg) { std::cout << std::fixed << arg << ' '; } // oops, this won't be called
}, v);
Les instructions de commutation sur les classes enum sont beaucoup plus sûres, car vous ne pouvez pas écrire une instruction case en utilisant une valeur qui ne fait pas partie de l'enum. De même, je pense qu'il serait très utile qu'un visiteur de variante soit limité à un sous-ensemble des types contenus dans la variante, plus un gestionnaire par défaut. Est-il possible d'implémenter quelque chose comme cela ?
EDIT : s/implicit cast/implicit conversion/
EDIT2 : J'aimerais avoir un "fourre-tout" significatif. [](auto)
gestionnaire. Je sais que sa suppression provoquera des erreurs de compilation si vous ne gérez pas tous les types de la variante, mais cela supprime également une fonctionnalité du modèle de visiteur.
0 votes
L'extrait juste au-dessus de celui-ci sur en.cppreference ne fait-il pas exactement ce que vous voulez ?
3 votes
Hier, j'ai appris qu'il n'existe pas de "cast implicite", car tous les cast sont explicites. La phrase que vous recherchez est "conversion implicite" :) stackoverflow.com/a/45672844/3560202
0 votes
@Holt, celui avec constexpr if ? Je pense qu'elle présente le même écueil.
1 votes
@kim366 merci. Dans tous les cas, cette fonctionnalité en C++ est une abomination :)
0 votes
@MichaBrzozowski Essayez-le, et essayez d'ajouter n'importe quel type à la variante, vous verrez que votre code ne compilera plus, même si le type est implicitement convertible en un autre (par exemple, essayez d'ajouter
char
).3 votes
Si vous fournissez
default
dans votreswitch
vous avez le même problème. (qui est l'équivalent deauto arg
ici).0 votes
Désolé que la question soit confuse. Ce que je veux dire, c'est que si vous mettez float au lieu de double dans la signature de la variante, le visiteur peut toujours avoir un gestionnaire double, et toute valeur float déclenchera le gestionnaire [](auto). Mon but est d'obtenir une erreur de compilation à la place. @Holt : J'ai essayé la même chose avec la version constexpr de if et la même chose se produit, vous vous retrouvez dans la dernière déclaration else.
0 votes
@MichaBrzozowski Et la dernière
else
est une erreur de compilation... Je ne vois pas ce que vous voulez faire que cette version ne fait pas ?0 votes
@Holt : dans ce cas, oui, mais vous aurez souvent une déclaration fourre-tout, tout comme la valeur par défaut : dans un commutateur.
1 votes
@MichaBrzozowski Vous voulez donc une erreur du compilateur lorsque vous cambiar votre code en principe, ce n'est pas possible... Le compilateur n'a pas la mémoire de la compilation précédente... Comment voulez-vous que le compilateur sache que vous voulez une erreur de compilation dans ce cas mais pas dans l'autre ? Quelle serait la différence entre ajouter
float
et en ajoutantstd::vector<float>
pour le compilateur ?0 votes
@Holt : déclarer un
enum class
puis rédiger un texte non exhaustif deswitch
sur celui-ci avec undefault
manipulateur. Modifiez ensuite le nom d'un élément de l'énumération pour qu'il devienne uncase
pour. Cela provoque une erreur de compilation, je veux la même chose ici.1 votes
BTW, je ne suis pas sûr qu'en situation réelle, il arrive souvent d'ajouter un nouveau type implicitement convertible dans l'élément
variant
.0 votes
@MichaBrzozowski Ce n'est pas la même chose qu'ajouter, c'est changer quelque chose, dans ce cas cela a plus de sens. Il suffit d'ajouter un
static_assert
au début de la lambda pour vérifier que seuls les types possibles sont pris en compte.2 votes
Cela peut être utile : youtube.com/watch?v=mqei4JJRQ7s&t=397s