Si tratta di un follow-up a std::unordered_map<T,std::unique_ptr<U>> copyable? GCC bug?modo corretto di fare is_copy_constructible per la resa contenitore falso se il tipo di fondo non è copia costruibili
Quindi immaginiamo abbiamo creato una classe template Container
:
template<class T>
class Container {
T t;
public:
Container() = default;
Container(const Container& other) : t(other.t) {}
};
Purtroppo, is_copy_constructible
per produce true
anche se T
non è copia costruibile:
static_assert(!std::is_copy_constructible<Container<std::unique_ptr<int>>>::value, "Copyable");
Questa affermazione fallisce per i motivi descritti nella risposta alla domanda precedente, anche here is another answer on this topic.
Sembra che questo può essere risolto rendendo il modello copia consructor come questo:
template<class T>
class Container {
T t;
public:
Container() = default;
template<typename U = void>
Container(const Container& other) : t(other.t) {}
};
Questo funziona sia in GCC e clang (static_assert
non manca più).
Le domande:
Dal punto di vista dello standard, questo è un modo corretto di fare
is_copy_constructible
lavoro? In caso affermativo, in che modo l'aggiunta del modello influisce sulla validità del contesto immediato dell'inizializzazione della variabile (§20.9.4.3/6
)?(opzionale) Esistono modi più corretti o più intuitivi per eseguire questa operazione?
Nota: la dichiarazione del costruttore di copie default
raggiunge anche questo obiettivo, ma non è sempre possibile.
UPDATE: Ora vedo che la mia soluzione non è valida perché il costruttore di copia non può essere un modello. Quella stanza lascia ancora per la domanda 2.
UPDATE 2: ho cambiato un po 'il codice da ecatmur's answer per spostare la bruttezza fuori Container
stesso e renderlo riutilizzabile:
struct unused; // forward declaration only
template<class Container>
using const_ref_if_copy_constructible = typename std::conditional<
std::is_copy_constructible<typename Container::value_type>::value,
Container const&,
unused>::type;
template<typename T>
class Container {
T t;
public:
typedef T value_type;
Container() = default;
Container(const_ref_if_copy_constructible<Container> other) : t(other.t) {}
Container(Container&& other) : t(std::move(other.t)) {}
};
Ma ancora non sono abbastanza soddisfatto di questo. Per me sembra un difetto nello standard C++ che cose del genere non funzionino fuori dagli schemi.
Essere consapevoli del fatto che "fare la copia ctor un modello" non dovrebbe realmente funzionare - un'istanza di una funzione di modello non è mai considerata una copia ctor, in modo che il compilatore dovrebbe aggiungere uno se tutto ciò che fornisci è il modello. – Angew