Pourquoi les fonctions supprimées par C ++ 11 participent-elles à la résolution de la surcharge?

Pourquoi C ++ 11 fait-il participer les fonctions ” delete d” à la résolution de la surcharge ?
Pourquoi est-ce utile? Ou en d’autres termes, pourquoi sont-ils cachés au lieu d’être entièrement supprimés?

La moitié de la syntaxe = delete pour but d’empêcher les personnes d’appeler certaines fonctions avec certains parameters. Cela permet principalement d’éviter les conversions implicites dans certains scénarios spécifiques. Pour interdire une surcharge particulière, il doit participer à la résolution de la surcharge.

La réponse que vous citez vous donne un exemple parfait:

 struct onlydouble { onlydouble(std::intmax_t) = delete; onlydouble(double); }; 

Si la delete supprime entièrement la fonction, cela rendrait la syntaxe = delete équivalente à ceci:

 struct onlydouble2 { onlydouble2(double); }; 

Vous pourriez faire ceci:

 onlydouble2 val(20); 

Ceci est légal C ++. Le compilateur examinera tous les constructeurs. aucun d’eux ne prend directement un type entier. Mais l’un d’eux peut le prendre après une conversion implicite. Alors ça va appeler ça.

 onlydouble val(20); 

Ce n’est pas légal C ++. Le compilateur examinera tous les constructeurs, y compris ceux de delete . Il verra une correspondance exacte, via std::intmax_t (qui correspondra exactement à tout littéral entier). Ainsi, le compilateur le sélectionnera et émettra immédiatement une erreur, car il a sélectionné une fonction de delete .

= delete signifie “je l’interdit”, pas simplement “ceci n’existe pas”. C’est une déclaration beaucoup plus forte.

Je demandais pourquoi le standard C ++ dit = delete signifie “je l’interdit” au lieu de “ceci n’existe pas”

C’est parce que nous n’avons pas besoin de grammaire spéciale pour dire “cela n’existe pas”. Nous obtenons cela implicitement en ne déclarant simplement pas le “ceci” en question. “Je l’interdis” représente une construction qui ne peut être réalisée sans une grammaire spéciale. Nous avons donc une grammaire spéciale pour dire “je l’interdis” et pas l’autre chose.

La seule fonctionnalité que vous obtiendriez en ayant une grammaire explicite “ceci n’existe pas” serait d’empêcher quelqu’un de le déclarer ultérieurement. Et ce n’est tout simplement pas assez utile pour avoir besoin de sa propre grammaire.

il n’y a pas d’autre moyen de déclarer que le constructeur de la copie n’existe pas, et son existence peut provoquer des ambiguïtés absurdes.

Le constructeur de copie est une fonction membre spéciale. Chaque classe a toujours un constructeur de copie. Tout comme ils ont toujours un opérateur d’affectation de copie, déplacez le constructeur, etc.

Ces fonctions existent; la question est seulement de savoir s’il est légal de les appeler. Si vous tentiez de dire que = delete signifiait qu’elles n’existaient pas, la spécification devrait expliquer ce que cela signifie pour une fonction qui n’existe pas. Ce n’est pas un concept que la spécification gère.

Si vous tentez d’appeler une fonction qui n’a pas encore été déclarée / définie, le compilateur sera en erreur. Mais il y aura une erreur à cause d’un identifiant non défini , pas à cause d’une erreur “fonction n’existe pas” (même si votre compilateur le signale de cette manière). Divers constructeurs sont tous appelés par une résolution de surcharge, leur “existence” est donc gérée à cet égard.

Dans tous les cas, il y a soit une fonction déclarée via identifiant, soit un constructeur / destructeur (également déclaré via identifiant, juste un identifiant de type). La surcharge de l’opérateur masque l’identifiant derrière le sucre syntaxique, mais il est toujours là.

La spécification C ++ ne peut pas gérer le concept d’une “fonction qui n’existe pas”. Il peut gérer une incompatibilité de surcharge. Il peut gérer une ambiguïté de surcharge. Mais il ne sait pas ce qu’il n’y a pas. Donc, = delete est défini en termes de beaucoup plus utiles “tentatives d’appeler cet échec” plutôt que les moins utiles “prétendent que je n’ai jamais écrit cette ligne”.

Et encore, relisez la première partie. Vous ne pouvez pas faire cela avec “la fonction n’existe pas”. C’est une autre raison pour laquelle il est défini de la manière suivante: l’un des principaux cas d’utilisation de la syntaxe = delete étant de pouvoir forcer l’utilisateur à utiliser certains types de parameters, à les convertir explicitement, etc. Fondamentalement, pour déjouer les conversions de types implicites.

Votre suggestion ne ferait pas cela.

Le C ++ Working Draft 2012-11-02 ne fournit aucune justification à cette règle, mais quelques exemples

8.4.3 Définitions supprimées [dcl.fct.def.delete]

3 [ Exemple : On peut imposer une initialisation non par défaut et une initialisation non intégrale avec

 struct onlydouble { onlydouble() = delete; // OK, but redundant onlydouble(std::intmax_t) = delete; onlydouble(double); }; 

exemple de fin ]
[ Exemple : On peut empêcher l’utilisation d’une classe dans certaines nouvelles expressions en utilisant les définitions supprimées d’un opérateur déclaré par l’utilisateur new pour cette classe.

 struct sometype { void *operator new(std::size_t) = delete; void *operator new[](std::size_t) = delete; }; sometype *p = new sometype; // error, deleted class operator new sometype *q = new sometype[3]; // error, deleted class operator new[] 

exemple de fin ]
[ Exemple : On peut rendre une classe impossible à doser, c.-à-d. Déplacer uniquement, en utilisant les définitions supprimées du constructeur de copie et de l’opérateur d’atsortingbution de copie, puis en fournissant les définitions par défaut du constructeur de déplacement et de l’opérateur d’affectation de déplacement.

 struct moveonly { moveonly() = default; moveonly(const moveonly&) = delete; moveonly(moveonly&&) = default; moveonly& operator=(const moveonly&) = delete; moveonly& operator=(moveonly&&) = default; ~moveonly() = default; }; moveonly *p; moveonly q(*p); // error, deleted copy constructor 

exemple de fin ]