J'essaie de trouver un moyen pratique d'initialiser les structures C ++ 'pod'. Maintenant, considérez la structure suivante:
struct FooBar {
int foo;
float bar;
};
// just to make all examples work in C and C++:
typedef struct FooBar FooBar;
Si je veux initialiser commodément ceci en C (!), Je pourrais simplement écrire:
/* A */ FooBar fb = { .foo = 12, .bar = 3.4 }; // illegal C++, legal C
Notez que je veux éviter explicitement la notation suivante, car elle me semble être faite pour me casser le cou si je change quoi que ce soit dans la structure à l'avenir:
/* B */ FooBar fb = { 12, 3.4 }; // legal C++, legal C, bad style?
Pour obtenir le même (ou au moins similaire) en C ++ que dans l' /* A */
exemple, je devrais implémenter un constructeur idiot:
FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar) {}
// ->
/* C */ FooBar fb(12, 3.4);
Ce qui est bon pour faire bouillir de l'eau, mais ne convient pas aux paresseux (la paresse est une bonne chose, non?). En outre, il est à peu près aussi mauvais que l' /* B */
exemple, car il n'indique pas explicitement quelle valeur va à quel membre.
Donc, ma question est essentiellement de savoir comment je peux réaliser quelque chose de similaire /* A */
ou meilleur en C ++? Sinon, je serais d'accord avec une explication pourquoi je ne devrais pas vouloir faire cela (c'est-à-dire pourquoi mon paradigme mental est mauvais).
ÉDITER
Par pratique , je veux dire également maintenable et non redondant .
la source
Réponses:
Les initialisations désignées seront prises en charge en c ++ 2a, mais vous n'avez pas à attendre, car elles sont officiellement prises en charge par GCC, Clang et MSVC.
GCC Demo MSVC Demo
la source
Puisque
style A
n'est pas autorisé en C ++ et que vous ne voulez pas, questyle B
diriez-vous d'utiliserstyle BX
:Au moins aider dans une certaine mesure.
la source
foo
etbar
dans le futur. C initialiserait toujours les champs souhaités, mais pas C ++. Et c'est le point de la question - comment obtenir le même résultat en C ++. Je veux dire, Python le fait avec des arguments nommés, C - avec des champs «nommés», et C ++ devrait avoir quelque chose aussi, j'espère.explicit FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar)
. Notez le mot-clé explicite . Même briser la norme est meilleur en matière de sécurité. Dans Clang: -Wno-c99-extensionsVous pouvez utiliser un lambda:
Plus d'informations sur cet idiome peuvent être trouvées sur le blog de Herb Sutter .
la source
fb.XXX = YYY
.Extraire les contants dans des fonctions qui les décrivent (refactoring de base):
Je sais que le style est très proche de celui que vous ne vouliez pas utiliser, mais il permet de remplacer plus facilement les valeurs constantes et de les expliquer également (donc pas besoin de modifier les commentaires), si jamais ils changent.
Une autre chose que vous pouvez faire (puisque vous êtes paresseux) est de rendre le constructeur en ligne, pour ne pas avoir à taper autant (en supprimant "Foobar ::" et le temps passé à basculer entre les fichiers h et cpp):
la source
Votre question est un peu difficile car même la fonction:
peut être appelé comme:
en raison des règles de promotion et de conversion pour les types numériques intégrés. (C n'a jamais été vraiment fortement typé)
En C ++, ce que vous voulez est réalisable, mais avec l'aide de modèles et d'assertions statiques:
En C, vous pouvez nommer les paramètres, mais vous n'irez jamais plus loin.
D'un autre côté, si vous ne voulez que des paramètres nommés, vous écrivez beaucoup de code encombrant:
Et vous pouvez ajouter une protection de promotion de type si vous le souhaitez.
la source
Les interfaces C ++ de nombreux compilateurs (y compris GCC et clang) comprennent la syntaxe de l'initialiseur C. Si vous le pouvez, utilisez simplement cette méthode.
la source
private: FooBar(float x, int y) {};
Encore une autre façon en C ++ est
la source
inline
!Option D:
FooBar FooBarMake(int foo, float bar)
C juridique, C ++ juridique. Facilement optimisable pour les POD. Bien sûr, il n'y a pas d'arguments nommés, mais c'est comme tout C ++. Si vous voulez des arguments nommés, Objective C devrait être un meilleur choix.
Option E:
C juridique, C ++ juridique. Arguments nommés.
la source
FooBar fb = {};
en C ++, il initialise par défaut tous les membres de la structure.Je sais que cette question est ancienne, mais il existe un moyen de résoudre cela jusqu'à ce que C ++ 20 apporte enfin cette fonctionnalité du C au C ++. Ce que vous pouvez faire pour résoudre ce problème, c'est utiliser des macros de préprocesseur avec static_asserts pour vérifier que votre initialisation est valide. (Je sais que les macros sont généralement mauvaises, mais ici je ne vois pas d'autre moyen.) Voir l'exemple de code ci-dessous:
Ensuite, lorsque vous avez une structure avec des attributs const, vous pouvez le faire:
C'est un peu gênant, car vous avez besoin de macros pour chaque nombre possible d'attributs et vous devez répéter le type et le nom de votre instance dans l'appel de macro. Vous ne pouvez pas non plus utiliser la macro dans une instruction return, car les assertions viennent après l'initialisation.
Mais cela résout votre problème: lorsque vous modifiez la structure, l'appel échouera au moment de la compilation.
Si vous utilisez C ++ 17, vous pouvez même rendre ces macros plus strictes en forçant les mêmes types, par exemple:
la source
Le chemin
/* B */
est correcte en C ++ et le C ++ 0x va étendre la syntaxe, donc il est également utile pour les conteneurs C ++. Je ne comprends pas pourquoi vous appelez ça du mauvais style?Si vous souhaitez indiquer des paramètres avec des noms, vous pouvez utiliser la bibliothèque de paramètres boost , mais cela peut dérouter quelqu'un qui ne le connaît pas.
La réorganisation des membres de structure est comme la réorganisation des paramètres de fonction, une telle refactorisation peut poser des problèmes si vous ne le faites pas très soigneusement.
la source
Et cette syntaxe?
Juste testé sur un Microsoft Visual C ++ 2015 et sur g ++ 6.0.2. Fonctionne bien.
Vous pouvez également créer une macro spécifique si vous souhaitez éviter de dupliquer le nom de la variable.
la source
clang++
3.5.0-10 avec-Weverything -std=c++1z
semble le confirmer. Mais ça n'a pas l'air bien. Savez-vous où la norme confirme qu'il s'agit d'un C ++ valide?ABCD abc = { abc.b = 7, abc.a = 5 };
.Pour moi, le moyen le plus paresseux d'autoriser l'initialisation en ligne est d'utiliser cette macro.
Cette macro crée un attribut et une méthode d'auto-référence.
la source