Quelles sont les Agrégats et les Gousses et comment/pourquoi sont-ils de spécial?
Ce FAQ est sur les Agrégats et les Gousses et couvre le matériel suivant:
- Quels sont Agrégats?
- Quels sont PODs (Plain Old Données)?
- Comment sont-ils liés?
- Comment et pourquoi sont-ils de spécial?
- Quels changements pour le C++11?
- Qu'est-ce que le POD sous-ensemble: stackoverflow.com/questions/146452/what-are-pod-types-in-c
Vous devez vous connecter pour publier un commentaire.
Comment lire:
Cet article est assez long. Si vous voulez savoir à propos de ces deux agrégats et Pod (Plain Old Données) prendre le temps de le lire. Si vous êtes intéressé seulement dans les agrégats, lire seulement la première partie. Si vous êtes intéressé dans les Gousses, puis vous devez d'abord lire la définition, implications et exemples d'agrégats et puis vous peut saut à Gousses, mais je voudrais encore vous recommandons la lecture de la première partie dans son intégralité. La notion d'agrégats est essentiel pour la définition des Gousses. Si vous trouvez des erreurs (même mineur, y compris la grammaire, la stylistique, de la mise en forme, la syntaxe, etc.) merci de laisser un commentaire, je vais modifier.
Cette réponse s'applique à C++03. Pour d'autres normes C++, voir:
Ce sont des agrégats et pourquoi ils sont spéciaux
Définition formelle de la norme C++ (C++03 8.5.1 §1):
Donc, OK, nous allons analyser cette définition. Tout d'abord, un tableau est un agrégat. Une classe peut aussi être un agrégat si... attendez! rien n'est dit sur les structures ou les syndicats, ne peuvent-ils pas être des agrégats? Oui, ils le peuvent. En C++, le terme
class
se réfère à toutes les classes, les structures et les syndicats. Ainsi, une classe (ou struct ou union) est un agrégat si et seulement si elle satisfait aux critères de l'définitions ci-dessus. Que faire de ces critères impliquent?Cela ne signifie pas un agrégat de classe ne peut pas avoir de constructeurs, en fait, il peut avoir un constructeur par défaut et/ou d'un constructeur de copie, aussi longtemps qu'ils sont déclarées implicitement par le compilateur, et non explicitement par l'utilisateur
Pas privés ou protégés non-membres de données statiques. Vous pouvez avoir autant d'privé et protégé des fonctions membres (mais pas les constructeurs) ainsi que de nombreux privés ou protégés statique membres de données et les fonctions de membres que vous le souhaitez et ne pas enfreindre les règles pour l'ensemble des classes
Un total classe peut avoir un utilisateur déclaré/défini par l'utilisateur de copier-opérateur d'affectation et/ou destructeur
Un tableau est un ensemble, même si c'est un ensemble de non-agrégation type de classe.
Maintenant regardons quelques exemples:
Vous obtenez l'idée. Maintenant, nous allons voir comment les agrégats sont spéciales. Ils, contrairement à la non-agrégation des classes, peut être initialisé avec des accolades
{}
. Cette syntaxe d'initialisation est communément connu pour les tableaux, et nous avons appris que ce sont des agrégats. Donc, nous allons commencer avec eux.Type array_name[n] = {a1, a2, …, am};
if(m == n)
le ième élément du tableau est initialisé avec uni
else if(m < n)
le premier m éléments du tableau sont initialisés avec un1,2, ...,m et l'autre
n - m
éléments sont, si possible, valeur initialisée (voir ci-dessous pour l'explication du terme)else if(m > n)
le compilateur émet une erreur
d'autre (c'est le cas lorsque n n'est pas spécifié comme
int a[] = {1, 2, 3};
)la taille de la matrice (n) est supposé être égal à m, de sorte
int a[] = {1, 2, 3};
est équivalent àint a[3] = {1, 2, 3};
Lorsqu'un objet de type scalaire (
bool
,int
,char
,double
, pointeurs, etc.) est valeur initialisée cela signifie qu'il est initialisé avec0
pour ce type (false
pourbool
,0.0
pourdouble
, etc.). Lorsqu'un objet de type classe avec un utilisateur déclaré dans le constructeur par défaut est la valeur initialisé son constructeur par défaut est appelé. Si le constructeur par défaut est implicitement défini, alors tous les membres non statiques sont récursivement la valeur d'initialisation. Cette définition est imprécise et un peu inexact, mais il devrait vous donner l'idée de base. Une référence ne peut pas être la valeur d'initialisation. La valeur d'initialisation pour un non-classe d'agrégation peut échouer si, par exemple, la classe a n'y a pas de constructeur par défaut.Exemples d'initialisation de tableau:
Maintenant, nous allons voir comment agréger les classes peuvent être initialisés avec des accolades. Peu de la même manière. Au lieu des éléments du tableau, nous allons initialiser les non-membres de données statiques dans l'ordre de leur apparition dans la définition de la classe (ils sont tout public, par définition). Si il y a moins d'initialiseurs que les membres, le reste est de la valeur d'initialisation. S'il est impossible de valeur d'initialisation de l'un des membres qui n'ont pas été explicitement initialisée, on obtient une erreur de compilation. Si il y a plus d'initialiseurs que nécessaire, on obtient une erreur de compilation ainsi.
Dans l'exemple ci-dessus
y.c
est initialisé avec'a'
,y.x.i1
avec10
,y.x.i2
avec20
,y.i[0]
avec20
,y.i[1]
avec30
ety.f
est la valeur d'initialisation, qui est initialisé avec0.0
. Les protégés de membre statiqued
n'est pas initialisé à tous, parce que c'eststatic
.Globale syndicats sont différentes que vous pouvez initialiser seulement leur premier membre avec des accolades. Je pense que si vous êtes assez avancée en C++ d'envisager d'utiliser des syndicats (leur utilisation peut être très dangereux et doit être pensé avec soin), vous pourriez chercher les règles pour les syndicats dans la norme vous-même :).
Maintenant que nous savons ce qui est spécial au sujet de agrégats, nous allons essayer de comprendre les restrictions sur les classes; c'est, pourquoi ils sont là. Nous devrions comprendre que memberwise d'initialisation avec des accolades implique que la classe n'est rien de plus que la somme de ses membres. Si un utilisateur défini par le constructeur est présent, cela signifie que l'utilisateur doit faire un travail supplémentaire pour initialiser les membres donc accolade de l'initialisation serait incorrect. Si les fonctions virtuelles sont présentes, cela signifie que les objets de cette classe ont (sur la plupart des implémentations) un pointeur vers la soi-disant vtable de la classe, qui est défini dans le constructeur, donc brace-initialisation serait insuffisant. Vous pourriez comprendre le reste de la restriction d'une manière semblable à un exercice :).
Donc assez sur les agrégats. Nous pouvons maintenant définir un ensemble plus strict de types, à savoir, les Gousses
Quels sont les Gousses et pourquoi ils sont spéciaux
Définition formelle de la norme C++ (C++03 9 §4):
Wow, celui-ci est plus difficile à analyser, n'est-ce pas? 🙂 Laissons les syndicats out (pour les mêmes raisons que ci-dessus) et de reformuler en un peu plus clair:
Quoi cette définition implique? (Ai-je mentionné POD signifie Plaine Anciennes Données?)
Exemples:
POD-classes, POD-les syndicats, les types scalaires, et les tableaux de ces types sont collectivement appelés POD-types.
Les gousses sont spéciaux à bien des égards. Je vais vous donner juste quelques exemples.
POD-classes sont les plus proches de C des structures. Contrairement à eux, les Gousses peuvent avoir des fonctions de membre et de l'arbitraire de membres statiques, mais aucun de ces deux changement de la disposition de la mémoire de l'objet. Donc, si vous voulez écrire plus ou moins portable bibliothèque dynamique qui peut être utilisé à partir de C et même .NET, vous devriez essayer de faire tout votre des fonctions exportées prendre et de ne renvoyer que les paramètres de POD-types.
La durée de vie des objets de la non-POD type de classe commence lorsque le constructeur a fini et se termine lorsque le destructeur de a fini. Pour la GOUSSE de classes, la vie commence lorsque le stockage de l'objet est occupé et se termine lorsque que le stockage est libéré ou réutilisés.
Pour les objets de types POD, il est garanti par la norme que lorsque vous
memcpy
le contenu de votre objet dans un tableau de char ou unsigned char, et puismemcpy
le contenu dans votre objet, il tiendra sa valeur d'origine. Notez qu'il n'y a aucune garantie pour les objets de la non-POD types. Aussi, vous pouvez copier POD objets avecmemcpy
. L'exemple suivant suppose que T est un module de type:instruction goto. Comme vous le savez peut-être, il est illégal (le compilateur doit émettre une erreur) de faire un saut par goto à partir d'un point où certaines variables n'était pas encore dans le champ d'application à un point où il est déjà dans le champ d'application. Cette restriction s'applique uniquement si la variable est de la non-type de POD. Dans l'exemple suivant
f()
est mal formé alors queg()
est bien formé. Notez que Microsoft compilateur est trop libérale à cette règle, il a juste un avertissement dans les deux cas.Il est garanti qu'il n'y aura pas de rembourrage dans le début d'une GOUSSE d'objet. En d'autres termes, si un module de classe du premier membre est de type T, vous pouvez en toute sécurité
reinterpret_cast
deA*
àT*
et obtenir le pointeur vers le premier membre et vice-versa.La liste continue encore et encore...
Conclusion
Il est important de comprendre ce qu'est exactement un POD est parce que de nombreuses fonctionnalités de langage, comme vous le voyez, de se comporter différemment pour eux.
private:
appropriée):struct A { int const a; };
puisA()
est bien formé, même siA
's de constructeur par défaut définition serait mal formé.:)
"Similarly, a POD-union is an aggregate union that has no .... types) or reference, and has ..."
. Lereference
sur le présent contexte, on entend uniquement les références ou il signifie aussi des pointeurs? I. e., elle est littérale ou même declass
:"In C++, the term class refers to all classes, structs, and unions."
?struct POD
encore un POD si j'ajouteint * pi;
ouchar * acName;
ou mêmeMyCustomClass * pObject;
?B b1[3] = {B()};
, comment se fait -B
est un agrégat de classe, étant donné qu'il est défini par l'utilisateur, le constructeur?Quels changements pour le C++11?
Agrégats
La définition standard d'un ensemble a légèrement changé, mais c'est toujours à peu près la même:
Ok, ce qui a changé?
Précédemment, un agrégat peut ne pas avoir de l'utilisateur déclaré les constructeurs, mais maintenant il ne peut pas avoir fourni par l'utilisateur constructeurs. Est-il une différence? Oui, il est, parce que maintenant vous pouvez déclarer les constructeurs et les par défaut eux:
C'est encore un agrégat parce qu'un constructeur (ou tout membre de la fonction) qui est par défaut sur la première déclaration n'est pas fourni par l'utilisateur.
Maintenant un total ne peut pas avoir de corset ou égal initialiseurs pour les non-membres de données statiques. Qu'est-ce que cela signifie? Eh bien, c'est simplement parce que cette nouvelle norme, nous pouvons initialiser directement les membres de la classe comme ceci:
L'utilisation de cette fonctionnalité rend la classe plus un agrégat parce que c'est essentiellement équivalente à la fourniture de votre propre constructeur par défaut.
Donc, ce qui est un agrégat n'a pas changé grand-chose. C'est toujours la même idée de base, adaptés aux nouvelles fonctionnalités.
Qu'en Dosettes?
Gousses suis passé par beaucoup de changements. Beaucoup de règles précédentes sur les Gousses ont été assouplies dans cette nouvelle norme, et la façon dont la définition est donnée dans la norme a été radicalement modifiée.
L'idée d'une GOUSSE de capture essentiellement deux propriétés distinctes:
De ce fait, la définition a été divisé en deux concepts distincts: trivial classes et standard-layout classes, car elles sont plus utiles que les POD. La norme utilise rarement le terme POD, préférant le plus spécifique trivial et standard-layout concepts.
La nouvelle définition de dit en gros qu'un POD est une classe qui est à la fois trivial et a standard-layout, et cette propriété doit tenir de manière récursive pour tous les non-membres de données statiques:
Reprenons chacun de ces deux propriétés en détail séparément.
Trivial classes
Trivial est la première propriété mentionnée ci-dessus: trivial classes de soutien initialisation statique.
Si une classe est trivialement copiable (un sur-ensemble de trivial classes), il est ok pour copier sa représentation sur la place avec des choses comme
memcpy
et attendre le résultat sera le même.La norme définit un trivial classe comme suit:
Donc, ce sont tous ceux trivial et non-triviales?
Fondamentalement, cela signifie que la copie ou le déplacement constructeur est trivial si il n'est pas fourni par l'utilisateur, la classe n'a rien de virtuel, et cette propriété détient de manière récursive pour tous les membres de la classe et de la classe de base.
La définition d'un banal copier/déplacer opérateur d'affectation est très similaire, il suffit de remplacer le mot "constructeur" avec "opérateur d'affectation".
Trivial destructeur a aussi une définition similaire, avec la contrainte qu'il ne peut pas être virtuel.
Et encore une autre règle similaire existe pour trivial constructeurs par défaut, avec l'ajout d'un constructeur par défaut n'est pas négligeable si la classe a non-membres de données statiques avec corset ou égal initialiseurs, qui nous l'avons vu ci-dessus.
Voici quelques exemples pour effacer tout:
Standard-layout
Standard-layout est la deuxième propriété. La norme mentionne le fait que ceux-ci sont utiles pour communiquer avec les autres langues, c'est parce qu'un standard-classe de mise en page a la même disposition de la mémoire de l'équivalent C struct ou union.
C'est une autre propriété qui doit tenir de manière récursive pour les membres et de toutes les classes de base. Et comme d'habitude, pas de fonctions virtuelles ou virtuel classes de base sont autorisés. Qui permettrait de faire la mise en page incompatible avec C.
Une ambiance détendue, la règle ici est que les classes de layout doit disposer de tous les non-membres de données statiques avec le même contrôle d'accès. Auparavant, ils devaient être tous public, mais maintenant vous pouvez les rendre privés ou protégés, aussi longtemps qu'ils sont tous privé ou tous protégé.
Lors de l'utilisation de l'héritage, un seul classe dans l'ensemble de l'arbre d'héritage peuvent avoir des non-membres de données statiques, et le premier non-membre de données statiques ne peuvent pas être d'une classe de base type (cela pourrait briser aliasing règles), sinon, ce n'est pas un standard-classe de mise en page.
C'est la façon dont la définition va dans le texte standard:
Et nous allons voir quelques exemples.
Conclusion
Avec ces nouvelles règles beaucoup plus de types peut être Gousses maintenant. Et même si un type n'est pas POD, nous pouvons profiter de quelques-uns de la GOUSSE de propriétés séparément (si c'est seulement un de banal ou standard-layout).
De la bibliothèque standard a les traits de tester ces propriétés dans l'en-tête
<type_traits>
:...a POD is a class that is both trivial and has standard-layout...
Il me semble que si une classe est trivial, toutes les données membres statiques doit être trivial, et si une classe a standard-layout, que tous les non-statique des données, les membres doivent avoir standard-layout. Est-il une raison pour spécifier...and this property must hold recursively for all non-static data members
? Plus précisément, est-il possible pour une classe d'être trivial et standard-layout, mais ne pas être un POD, ou pour une classe de non-trivial ou non standard-layout, mais encore un POD?Ce qui a changé pour le C++14
Nous pouvons nous référer à la Projet de C++14 standard de référence.
Agrégats
Ce qui est couvert dans la section
8.5.1
Agrégats qui nous donne la définition suivante:Le seul changement, c'est maintenant l'ajout de dans-membre de la classe des initialiseurs ne pas faire une classe non-agrégées. L'exemple suivant de C++11 agrégation d'initialisation pour les classes avec les membres de l'in-pace initialiseurs:
n'était pas un agrégat en C++11, mais c'est en C++14. Ce changement est couvert dans N3605: Membre des initialiseurs et agrégats, qui est la suivante résumé:
POD reste le même
La définition de POD(plaine anciennes données) struct est couvert dans la section
9
Classes qui dit:qui est le même libellé que C++11.
Standard-Modifications de Mise en page pour le C++14
Comme indiqué dans les commentaires pod repose sur la définition de standard-layout et qui a changé pour le C++14, mais c'était par défaut des rapports qui ont été appliqués à C++14 après le fait.
Il y avait trois DRs:
Donc standard-layout est passé de cette Pré C++14:
À dans C++14:
Je vais essayer:
C'est simple: tous les non-membres de données statiques doivent tous être
public
,private
, ouprotected
. Vous ne pouvez pas avoir certainspublic
et certainsprivate
.Le raisonnement pour eux va pour le raisonnement pour avoir une distinction entre le "modèle standard" et "pas de mise en page standard" à tous. À savoir, donner le compilateur de la liberté de choisir la façon de mettre les choses en mémoire. Ce n'est pas seulement à propos de vtable des pointeurs.
En arrière quand ils normalisée C++ en 98, ils avaient pour l'essentiel à prédire comment les gens allaient le mettre en œuvre. Alors qu'ils avaient tout à fait un peu de mise en œuvre de l'expérience avec les différentes versions de C++, ils n'étaient pas certaines choses. Ils ont donc décidé de faire preuve de prudence: donner les compilateurs autant de liberté que possible.
C'est pourquoi la définition de la POD en C++98 est aussi stricte. Il a donné des compilateurs C++ d'une grande latitude aux etats de mise en page pour la plupart des classes. Fondamentalement, POD types étaient destinés à être des cas particuliers, quelque chose que vous spécifiquement écrit pour une raison.
Quand C++11 est en cours d'élaboration, ils avaient beaucoup plus d'expérience avec les compilateurs. Et ils se sont rendu compte que... compilateur C++ les écrivains sont vraiment paresseux. Ils avaient tous cette liberté, mais ils n'ont pas ne quelque chose avec elle.
Les règles de mise en page standard, sont plus ou moins la codification de la pratique courante: la plupart des compilateurs n'ont pas à changer grand-chose, sinon rien du tout pour les mettre en œuvre (en dehors peut-être quelques trucs pour le type correspondant traits).
Maintenant, quand il est venu à
public
/private
, les choses sont différentes. La liberté de réorganiser les membrespublic
vsprivate
en fait peut importe pour le compilateur, en particulier dans le débogage de builds. Et depuis le point de standard de mise en page est qu'il y a la compatibilité avec d'autres langues, vous ne pouvez pas avoir la mise en page différents dans le debug vs libération.Ensuite, il ya le fait qu'il n'a pas vraiment de mal à l'utilisateur. Si vous effectuez un encapsulé classe, les chances sont bonnes que toutes vos données membres seront
private
de toute façon. Vous n'avez généralement pas exposer les données publiques des membres entièrement encapsulé types. Donc, ce ne serait qu'un problème pour les quelques utilisateurs qui ne veulent faire, qui veulent que la division.Donc c'est pas une grosse perte.
La raison pour cela on en revient à la raison normalisé standard de mise en page nouveau: pratique courante.
Il y a pas pratique courante quand il s'agit d'avoir deux membres d'un arbre d'héritage qui en fait stocker des choses. Certains mettent de la classe de base avant de la dérivée, d'autres le font dans l'autre sens. De quelle manière avez-vous les membres s'ils sont issus de deux classes de base? Et ainsi de suite. Les compilateurs divergent grandement sur ces questions.
Aussi, grâce à la zéro/un/l'infini de la règle, une fois que vous dites que vous pouvez avoir deux classes avec les membres, vous pouvez dire autant que vous le souhaitez. Cela nécessite l'ajout d'un grand nombre de règles de présentation pour savoir comment gérer cela. Que vous avez à dire comment l'héritage multiple, les œuvres, les classes qui mettent leurs données avant d'autres classes, etc. C'est beaucoup de règles, pour très peu de gain matériel.
Vous ne pouvez pas faire tout ce qui ne disposent pas de fonctions virtuelles et un constructeur par défaut de mise en page standard.
Je ne peux pas vraiment parler de celui-ci. Je ne suis pas suffisamment instruits en C++de l'aliasing règles de vraiment les comprendre. Mais il a quelque chose à voir avec le fait que la base de membres partagent la même adresse que la classe de base lui-même. Qui est:
Et c'est probablement contre C++aliasing règles. D'une certaine façon.
Cependant, pensez à ceci: quelle utilité pourrait avoir la capacité de faire cela jamais fait être? Depuis seulement une classe peut avoir des non-membres de données statiques, puis
Derived
doit être la classe (car il a uneBase
en tant que membre). DoncBase
doit être vide (de données). Et siBase
est vide, ainsi que une classe de base... pourquoi un membre de données de tout?Depuis
Base
est vide, il n'a pas d'état. De sorte que toute non-fonctions membres statiques vont faire ce qu'ils en fonction de leurs paramètres, de ne pas leurthis
pointeur.Donc encore une fois: pas de grosse perte.
static_cast<Base*>(&d)
et&d.b
sont les mêmesBase*
type, ils ont des points à des choses différentes et de briser ainsi le crénelage de la règle. Merci de me corriger.Derived
doit être la classe?Derived
's premier membre à sa classe de base, il faut deux choses: une classe de base, et d'un membre. Et depuis une seule classe dans la hiérarchie peut avoir des membres (et des standard-layout), ce qui signifie que sa classe de base ne peut pas avoir des membres.Changements en C++17
Télécharger le C++17 projet final de Norme Internationale ici.
Agrégats
C++17 se développe et améliore des agrégats et granulats d'initialisation. La bibliothèque standard comprend également un
std::is_aggregate
type de trait de classe. Voici la définition officielle de la section 11.6.1.1 et 11.6.1.2 (références internes élidée):Ce qui a changé?
Trivial Classes
La définition de trivial classe a été retravaillée en C++17 à l'adresse de plusieurs défauts qui n'ont pas été abordées dans le C++14. Les modifications sont de nature technique. Voici la nouvelle définition au 12.0.6 (références internes élidée):
Changements:
std::memcpy
. C'était une sémantique de contradiction, parce que, par définition comme supprimé tous les constructeur/opérateurs d'affectation, le créateur de la classe clairement prévu que la classe n'a pas pu être copié/déplacé, mais la classe quand même de rencontrer la définition d'un trivialement copiable classe. Donc en C++17, nous avons une nouvelle clause stipulant que trivialement copiable classe doit avoir au moins un trivial, non supprimés (mais pas forcément accessible au public) copier/déplacer constructeur/opérateur d'affectation. Voir N4148, DR1734Standard-layout Classes
La définition de la norme de mise a également été retravaillé à l'adresse des rapports de défaut. De nouveau, les changements étaient de nature technique. Voici le texte de la norme (12.0.7). Comme auparavant, les références internes sont gommés:
Changements:
Remarque: Le C++ comité des normes prévu les changements ci-dessus basées sur des rapports de défaut à appliquer à C++14, bien que la nouvelle langue n'est pas dans la publication du C++14 standard. C'est dans le C++17 standard.
Ce qui va changer pour le C++20
C'est encore tôt, de sorte que certains de cette réponse pourrait changer dans le futur. Suivant le reste du thème qui ressort de cette question, la signification et l'utilisation des agrégats continue à changer à chaque norme. Il y a plusieurs changements à l'horizon.
Types de l'utilisateur déclaré constructeurs P1008
En C++17, ce type est toujours un agrégat:
Et, par conséquent,
X{}
encore compile parce que c'est agrégée d'initialisation - pas un constructeur invocation. Voir aussi: Quand un constructeur privé pas un constructeur privé?En C++20, la restriction de changement d'exiger:
à
Cela a été adoptée dans le C++20 du projet de travail. Ni le
X
ici, ni laC
dans la question sera agrégats en C++20.Cela fait aussi un effet yo-yo avec l'exemple suivant:
En C++11/14,
B
était pas un agrégat en raison de la classe de base, de sorteB{}
effectue la valeur d'initialisation qui appelleB::B()
qui appelleA::A()
, à un point où il est accessible. Cela a été bien formé.En C++17,
B
est devenu un agrégat parce que les classes de base ont été autorisés, ce qui faitB{}
globale de l'initialisation. Cela nécessite copie de la liste d'initialisation d'unA
de{}
, mais en dehors du contexte deB
, où il n'est pas accessible. En C++17, c'est mal formé (auto x = B();
serait bien tout de même).En C++20 maintenant, en raison de la règle ci-dessus changement,
B
une fois de plus, cesse d'être un agrégat (pas à cause de la classe de base, mais à cause de l'utilisateur déclaré dans le constructeur par défaut - même si c'est par défaut). Donc, on en revient à passer parB
s'constructeur, et ce fragment devient bien formé.De l'initialisation d'agrégats à partir d'une mise entre parenthèses de la liste de valeurs P960
Un problème commun qui se lève, c'est vouloir utiliser
emplace()
style de constructeurs avec des agrégats:Cela ne fonctionne pas, parce que
emplace
va essayer de bien effectuer l'initialisationX(1, 2)
, ce qui n'est pas valide. La solution habituelle est d'ajouter un constructeur àX
, mais avec cette proposition (actuellement en train de travailler son chemin à travers la Base), les agrégats efficacement avons synthétisé les constructeurs qui font la bonne chose - et de se comporter comme des constructeurs. Le code ci-dessus va compiler en tant que-est en C++20 (en supposant que cette fonctionnalité soit approuvée, ce qui semble probable).Modèle de classe Argument Déduction (CTAD) pour les Agrégats P1021
En C++17, cela ne compile pas:
Les utilisateurs auraient à écrire leur propre déduction guide pour la totalité des modèles:
Mais comme c'est dans un certain sens, "la chose la plus évidente" à faire, et qui est fondamentalement juste standard, la langue va le faire pour vous. Ce changement a été approuvé par l'Évolution, en novembre 2018, de sorte que l'exemple ci-dessus va probablement compiler en C++20 (sans le besoin de l'utilisateur fourni par déduction guide).