O è stato un mio errore, o sono stato citato in modo errato, e onestamente non ricordo quale.
Tuttavia, ho questo consiglio molto ferma posizione sul tema:
Non utilizzare is_trivial
né is_trivially_copyable
! MAI!!!
Anziché utilizzare uno di questi:
is_trivially_destructible<T>
is_trivially_default_constructible<T>
is_trivially_copy_constructible<T>
is_trivially_copy_assignable<T>
is_trivially_move_constructible<T>
is_trivially_move_assignable<T>
Motivazione:
TLDR: Vedere questo excellent question and correct answer.
Nessuno (me compreso) può ricordare la definizione di is_trivial
e is_trivially_copyable
. E se ti capita di cercarlo, e poi impiegarlo per 10 minuti ad analizzarlo, può o non può fare ciò che pensi intuitivamente che faccia. E se riesci ad analizzarlo correttamente, CWG potrebbe cambiare la sua definizione con poca o nessuna notifica e invalidare il tuo codice.
Utilizzare is_trivial
e is_trivially_copyable
sta giocando con il fuoco.
Tuttavia questi:
is_trivially_destructible<T>
is_trivially_default_constructible<T>
is_trivially_copy_constructible<T>
is_trivially_copy_assignable<T>
is_trivially_move_constructible<T>
is_trivially_move_assignable<T>
fanno esattamente quello che suonano come fanno, e non è probabile che mai hanno cambiato la loro definizione. Può sembrare eccessivamente prolisso avere a che fare con ciascuno dei membri speciali individualmente. Ma ripagherà nella stabilità/affidabilità del tuo codice. E se è necessario, impacchetta questi tratti individuali in un tratto personalizzato.
Aggiornamento
Per esempio, clang & gcc compilare questo programma:
#include <type_traits>
template <class T>
void
test()
{
using namespace std;
static_assert(!is_trivial<T>{}, "");
static_assert(is_trivially_copyable<T>{}, "");
static_assert(is_trivially_destructible<T>{}, "");
static_assert(is_destructible<T>{}, "");
static_assert(!is_trivially_default_constructible<T>{}, "");
static_assert(!is_trivially_copy_constructible<T>{}, "");
static_assert(is_trivially_copy_assignable<T>{}, "");
static_assert(!is_trivially_move_constructible<T>{}, "");
static_assert(is_trivially_move_assignable<T>{}, "");
}
struct X
{
X(const X&) = delete;
};
int
main()
{
test<X>();
}
noti che X
è banalmente copiabile, ma non banalmente copiare costruibile. Per quanto ne so, questo è un comportamento conforme.
VS-2015 attualmente dice che X
è né banalmente copiabile né banalmente copiabile. Credo che questo sia sbagliato secondo le specifiche attuali, ma sicuramente corrisponde a ciò che mi dice il mio buon senso.
Se avevo bisogno di memcpy
-inizializzato memoria, mi fiderei is_trivially_copy_constructible
sopra is_trivially_copyable
mi assicurare che una tale operazione sarebbe stato ok. Se volevo memcpy
a inizializzato memoria, vorrei controllare is_trivially_copy_assignable
.
Sembra che questo sia solo qualcosa che Howard ha detto durante la discussione, probabilmente senza pensarci su? – SergeyA
Sei sicuro che 'std :: mutex' è banalmente copiabile? Per lo standard che copiano il costruttore e l'assegnazione della copia sono entrambi contrassegnati come 'delete'. – NathanOliver
@NathanOliver Questo è il punto di LWG 1734. (Anche se hai ragione - il 'mutex' non è banalmente riproducibile.) Il suo distruttore non è banale.) – Columbo