Qual è il motivo per cui std :: memcpy non è constexpr anche in C ++ 20?
Capisco che la copia di blocchi arbitrari di memoria non è sempre possibile in fase di compilazione, ma poiché stiamo ottenendo constexpr constainer, metodi virtuali e anche algoritmi, perché non anche memcpy? È anche una specie di algoritmo.
Inoltre,
- C ++ 20
std::bit_castsembra unastd::memcpysoluzione alternativa,reinterpret_castma lo èconstexpr. std::copyl'uso di iteratori è contrassegnato comeconstexprC ++ 20, quindi la copia è in qualche modo possibile per i tipi.
L'utilizzo sarebbe quello di copiare o semplicemente "reinterpretare" variabili / array nelle constexprfunzioni, il primo non è risolto da std::bit_castAFAIK. In particolare, la domanda e la mia risposta vorrebbero usarla.
- C'è qualche motivo particolare per cui
std::bit_castpuò essere constexpr mastd::memcpynon può? - Ha a che fare con memcpy che usa puntatori void invece di riferimenti digitati?
- Non devi effettivamente copiare nulla?
- Compatibilità con le versioni precedenti di C?
- Forse perché non c'è il supporto per un "puntatore alla memoria constexpr"? Ma lo stesso vale per il parametro di riferimento in
std::bit_caste gli iteratori instd::copy.
La risposta pertinente a C ++ 20 bit_cast vs reinterpret_cast cita brevemente da qualche parte:
Inoltre, è attualmente impossibile implementare una funzione bit-cast constexpr, poiché memcpy stesso non è constexpr. Contrassegnare la funzione proposta come constexpr non richiede o impedisce a memcpy di diventare constexpr, ma richiede il supporto del compilatore. Ciò lascia le implementazioni libere di utilizzare la propria soluzione interna (ad esempio LLVM ha un codice operativo bitcast).
Ma non entra nei dettagli di non renderlo constexpr anche.
Nota, che non chiedo perché std::bit_castesiste. Mi piace, fornisce una chiara intenzione invece di una std::memcpysoluzione alternativa.
Risposte
Il modello a oggetti C ++ nel codice runtime è generalmente trattato in modo un po 'sciolto. Ha regole abbastanza rigide, ma ci sono un sacco di backdoor che sono consentite o dichiarate UB. Quest'ultimo significa che puoi ancora scrivere codice per farlo, ma C ++ non garantisce nulla sul comportamento di quel codice.
Nella valutazione costante (aka: esecuzione del codice in fase di compilazione), questo non è il caso. Le restrizioni constexprsono specificatamente intese per consentire al modello a oggetti di essere una cosa reale che devi seguire, senza backdoor praticabili. E anche quelli che occasionalmente consente sono esplicitamente richiesti di essere mal formati e produrre un errore di compilazione, piuttosto che tacere UB.
Fondamentalmente in fase di esecuzione, puoi trattare la memoria come solo byte di archiviazione. In fase di compilazione, non puoi ; non ti è permesso. Anche con l'allocazione dinamica nel constexprcodice aggiunto in C ++ 20, non puoi giocare a molti dei giochi che di solito riesci a giocare con quel genere di cose.
memcpysi occupa di byte di archiviazione, copiandoli avanti e indietro senza avere idea di cosa significano. bitcast conosce sia gli oggetti di origine che quelli di destinazione e non ti permetterà di farlo a meno che gli oggetti di origine e di destinazione non siano appropriati per l' bitcasting (cioè: banalmente copiabili).
bitcastha anche restrizioni molto specifiche sul contenuto di entrambi questi oggetti se vuoi che funzioni in fase di compilazione. In particolare, non puoi bitcastpuntatori o oggetti contenenti puntatori di alcun tipo. O riferimenti.
Questo perché i puntatori in fase di compilazione non sono solo indirizzi. Per catturare UB, un puntatore in fase di compilazione deve conoscere il vero tipo dinamico dell'oggetto a cui punta. Quindi le conversioni del puntatore che convertono solo l'indirizzo non sono consentite in fase di compilazione.
Questo è più un commento che una risposta poiché sto solo citando ciò che è scritto in P0202R0: Aggiungi i modificatori Constexpr alle funzioni in e Headers , ma lo scrivo qui perché non si adatta ai commenti:
B.
std::memmoveestd::memcpydeve avere constexpr aggiunte
std::memmoveestd::memcpyaccettarevoid*econst void*parametri. Questo li rende impossibili da implementare in puro C ++ comeconstexpr, perché le espressioni costanti non possono valutare una conversione da tipocv void *a tipo puntatore a oggetto secondo [expr.const].
Tuttavia, queste funzioni non sono solo popolari, ma sono anche ampiamente utilizzate nella libreria standard per ottenere prestazioni migliori. Non renderli constexpr costringerà lo sviluppatore della libreria standard ad avere comunque gli intrinseci del compilatore per loro. Questo è un passo difficile che deve essere fatto.
La relativa sezione di [expr.const]:
8.6 Espressioni costanti [expr.const]
[…] Un'espressioneeè un'espressione costante di base a meno che la valutazione die, seguendo le regole della macchina astratta (6.8.1), valuti una delle seguenti espressioni:
[…]
(2.13) - una conversione da tipocv void*a tipo puntatore a oggetto ;