Perché le funzioni cancellate da C ++ 11 partecipano alla risoluzione di sovraccarico?

Perché C ++ 11 fa in modo che le funzioni ” delete d” partecipino alla risoluzione di sovraccarico ?
Perché è utile? O in altre parole, perché sono nascosti invece di essere completamente cancellati?

La metà dello scopo di = delete syntax è di essere in grado di impedire alle persone di chiamare determinate funzioni con determinati parametri. Questo è principalmente per prevenire conversioni implicite in determinati scenari specifici. Per evitare un sovraccarico particolare, deve partecipare alla risoluzione del sovraccarico.

La risposta che citi ti offre un esempio perfetto:

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

Se delete rimosso completamente la funzione, ciò renderebbe la syntax = delete equivalente a questo:

 struct onlydouble2 { onlydouble2(double); }; 

Potresti fare questo:

 onlydouble2 val(20); 

Questo è legale C ++. Il compilatore guarderà tutti i costruttori; nessuno di loro prende direttamente un tipo intero. Ma uno di loro può prenderlo dopo una conversione implicita. Quindi lo chiamerà.

 onlydouble val(20); 

Questo non è un C ++ legale. Il compilatore esaminerà tutti i costruttori, inclusi quelli di delete . Vedrà una corrispondenza esatta, tramite std::intmax_t (che corrisponderà esattamente a qualsiasi intero letterale). Quindi il compilatore lo selezionerà e quindi emetterà immediatamente un errore, perché ha selezionato una funzione di delete d.

= delete significa “Lo proibisco”, non semplicemente “Questo non esiste”. È una dichiarazione molto più forte.

Stavo chiedendo perché lo standard C ++ dice = cancella significa “Io proibisco questo” invece di “questo non esiste”

È perché non abbiamo bisogno di una grammatica speciale per dire “questo non esiste”. Otteniamo questo implicitamente semplicemente non dichiarando il particolare “questo” in questione. “Io proibisco questo” rappresenta un costrutto che non può essere raggiunto senza una grammatica speciale. Quindi otteniamo una grammatica speciale per dire “Io proibisco questo” e non l’altra cosa.

L’unica funzionalità che si otterrebbe avendo una esplicita grammatica “questo non esiste” sarebbe quella di impedire a qualcuno di dichiararlo successivamente. E questo non è abbastanza utile per aver bisogno della sua stessa grammatica.

altrimenti non c’è modo di dichiarare che il costruttore di copie non esiste, e la sua esistenza può causare ambiguità senza senso.

Il costruttore di copie è una funzione membro speciale. Ogni class ha sempre un costruttore di copie. Così come hanno sempre un operatore di assegnazione delle copie, spostare il costruttore, ecc.

Queste funzioni esistono; la domanda è solo se è legale chiamarli. Se hai provato a dire che = delete significava che non esistevano, allora la specifica dovrebbe spiegare cosa significa che una funzione non esiste. Questo non è un concetto che la specifica gestisce.

Se si tenta di chiamare una funzione che non è stata ancora dichiarata / definita, il compilatore eseguirà un errore. Ma sarà errore a causa di un identificatore indefinito , non a causa di un errore “la funzione non esiste” (anche se il compilatore lo segnala in quel modo). Vari costruttori sono tutti chiamati per risoluzione di sovraccarico, quindi la loro “esistenza” viene gestita a tale riguardo.

In ogni caso, esiste una funzione dichiarata tramite identificatore, o un costruttore / distruttore (anch’esso dichiarato tramite identificatore, solo un identificatore di tipo). L’overloading dell’operatore nasconde l’identificatore dietro lo zucchero sintattico, ma è ancora lì.

La specifica C ++ non può gestire il concetto di una “funzione che non esiste”. Può gestire una mancata corrispondenza del sovraccarico. Può gestire un’ambiguità di sovraccarico. Ma non sa cosa non ci sia. Quindi = delete è definita in termini di “tentativi di chiamare questo fallire” molto più utili piuttosto che “meno male che pretendo di non aver mai scritto questa frase”.

E ancora, rileggi la prima parte. Non puoi farlo con “la funzione non esiste”. Questo è un altro motivo per cui è definito in questo modo: perché uno dei principali casi d’uso della syntax = delete è quello di essere in grado di forzare l’utente a usare determinati tipi di parametro, a cast esplicito e così via. Fondamentalmente, per sventare conversioni di tipo implicito.

Il tuo suggerimento non lo farebbe.

La bozza di lavoro C ++ 2012-11-02 non fornisce una spiegazione logica alla base di questa regola, solo alcuni esempi

8.4.3 Definizioni cancellate [dcl.fct.def.delete]

3 [ Esempio : si può forzare l’inizializzazione non predefinita e l’inizializzazione non integrale con

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

esempio finale ]
[ Esempio : si può impedire l’uso di una class in certe nuove espressioni utilizzando definizioni cancellate di un operatore dichiarato dall’utente nuovo per quella class.

 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[] 

esempio finale ]
[ Esempio : Si può rendere una class non percorribile, cioè solo mossa, usando le definizioni cancellate del costruttore di copie e dell’operatore di assegnazione copia, e quindi fornendo le definizioni predefinite del costruttore di movimento e dell’operatore di spostamento delle assegnazioni.

 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 

esempio finale ]