Voglio usare l'idioma pimpl per evitare che gli utenti della mia libreria abbiano bisogno delle nostre dipendenze esterne (come boost, ecc.) Tuttavia quando la mia classe è basata su modelli che sembra impossibile perché i metodi devono essere nel intestazione. C'è qualcosa che posso fare invece?pimpl per una classe di modelli
risposta
Se la classe è basata su modelli, gli utenti devono essenzialmente compilarlo (e questo è letteralmente vero nelle implementazioni C++ più utilizzate) e quindi hanno bisogno delle vostre dipendenze esterne.
La soluzione più semplice consiste nel mettere la maggior parte dell'implementazione della classe in una classe base non modello (o oggetto membro incapsulato di qualche classe). Risolvi il problema di nascondere il modulo lì.
E quindi scrivere la classe derivata (o allegata) per aggiungere sicurezza al tipo.
Ad esempio, supponiamo di avere un modello che fornisce la sorprendente capacità di allocare al primo accesso (omettendo il costruttore di copia necessario, l'assegnazione, distruttore):
template <class T>
class MyContainer
{
T *instance_;
public:
MyContainer() : instance_(0) {}
T &access()
{
if (instance_ == 0)
instance_ = new T();
return *instance_;
}
};
Se si voleva la "logica" essere separati in una classe di base non-modello, che avrebbe dovuto parametrizzare il comportamento in modo non-template, vale a dire, utilizzare le funzioni virtuali:
class MyBase
{
void *instance_;
virtual void *allocate() = 0;
public:
MyBase() : instance_(0) {}
void *access()
{
if (instance_ == 0)
instance_ = allocate();
return instance_;
}
};
Quindi è possibile aggiungere il tipo di consapevolezzanello strato esterno:
template <class T>
class MyContainer : MyBase
{
virtual void *allocate()
{ return new T(); }
public:
T &access()
{ return *(reinterpret_cast<T *>(MyBase::access())); }
};
cioè si utilizza funzioni virtuali che consente al modello di "riempire" le operazioni di tipo-dipendente. Ovviamente questo schema avrebbe davvero senso solo se si ha una logica di business che vale la pena di nascondersi.
È possibile creare esplicitamente un'istanza di modelli nel file di origine, ma ciò è possibile solo se si conosce quale sarà il tipo di modello. Altrimenti, non usare l'idioma pimpl per i modelli.
Qualcosa di simile a questo:
header.hpp:
#ifndef HEADER_HPP
#define HEADER_HPP
template< typename T >
class A
{
// constructor+methods + pimpl
};
#endif
sorgente.cpp:
#include "header.hpp"
// implementation
// explicitly instantiate for types that will be used
template class A<int>;
template class A<float>;
// etc...
-1 Non utilizzare 'auto_ptr' per PIMPL (è ** comportamento non definito ** per istanziare' auto_ptr' con un tipo incompleto). Funziona se si definiscono sia il costruttore che il distruttore per la classe esterna. Ma in quel caso non hai bisogno di un puntatore intelligente. –
@ AlfP.Steinbach unique_ptr? O solo un puntatore crudo? –
Sì, sia OK (anche se non sono sicuro dei dettagli su come usare 'unique_ptr' in questo caso, vorrei solo usare' shared_ptr' e accettare il sovraccarico come il costo di non richiedere alle persone di leggere la stampa fine nel standard). Cheers, –
ci sono due soluzioni generali:
mentre l'interfaccia dipende da così il mio tipo
T
, rimanda a un'implementazione più debolmente tipizzata (ad es. uno usando i puntatorivoid*
direttamente o tramite cancellazione del tipo) osi supporta solo un numero specifico e piuttosto limitato di tipi.
La seconda soluzione è pertinente per es. char
/wchar_t
-roba indipendente.
La prima soluzione è stata abbastanza comune nei primi giorni di template C++, perché a quel tempo i compilatori non erano buone a riconoscere punti in comune nel codice macchina generato, e introdurrebbe cosiddetto “ codice bloat ”. Oggi, con grande sorpresa di qualsiasi novizio che lo provi, una soluzione basata su modelli può spesso avere un ingombro di codice macchina inferiore rispetto a una soluzione basata sul polimorfismo di runtime. Certo, YMMV.
Acclamazioni & hth.,
La modifica tentata di qualcuno ha suggerito di rimuovere l'elaborazione "direttamente o tramite cancellazione di tipo" e "specifica e ..." qualificazione. L'elaborazione è necessaria per il significato e la qualifica è necessaria per la correttezza. L'attuale risposta accettata come soluzione è un esempio di "direttamente". Non c'è ancora nessun esempio di "cancellazione del tipo", e l'unica menzione è in questa risposta; sarebbe un peccato se qualcuno fosse riuscito a cancellarlo. –
- 1. Membri privati in classe Pimpl?
- 2. Allocazione PIMPL e stack
- 3. Pimpl + QSharedPointer - Destructor = Disaster
- 4. Come misurare i candidati Pimpl?
- 5. L'idioma di Pimpl è utilizzato in C#?
- 6. In classe inizializzatori utilizzando = per i modelli di classe
- 7. Pimpl con puntatori intelligenti in una classe con un costruttore modello: strano tipo incompleto problema
- 8. È un buon posto per usare il modello PIMPL?
- 9. Inizializzazione di membri statici di una classe basata su modelli
- 10. Funzione statica non basata su modelli in classe di modelli
- 11. Sovraccarico dell'operatore binario su una classe di modelli
- 12. Pimpl senza heap. Errato o superstizione?
- 13. Cython: modelli in wrapper di classe python
- 14. Includi modelli derivati Classe correlata
- 15. C++ Classe eredità e modelli
- 16. Dichiarare oggetto "contenitore" da modelli template classe e modelli variadic
- 17. Consigli per i modelli di modelli
- 18. Implementazione di pImpl con quantità minima di codice
- 19. Capture questo attributo lambda all'interno di una classe su modelli vs classe non-template
- 20. mantenendo le parti private esterne alle intestazioni C++: pura classe base virtuale vs pimpl
- 21. C++ esplicito modello di specializzazione del costruttore su modelli di classe su modelli
- 22. Due modelli variadici per una singola funzione?
- 23. Utilizzo di una vista singola per i modelli mvc derivati
- 24. Inizializzazione di membri cost const nella classe di modelli
- 25. Utilizzo di una tabella di ricerca per i modelli regex
- 26. Modelli per AS3 (come C++)
- 27. Vantaggio di modelli t4 su file di classe
- 28. Modelli di due modelli in una vista: Backbone/Marionette
- 29. Come posso creare uno slot in una classe S4 per modelli lineari robusti?
- 30. Una tabella - due modelli
credo che questo approccio potrebbe essere utile anche se non si desidera che le definizioni del preprocessore ('# define'), costanti ecc per essere visibile. Come sviluppatore, non voglio vedere i dettagli di implementazione di una classe/libreria che sto usando, specialmente nella lista di completamento automatico. Potresti voler nascondere quelli anche se la tua logica aziendale non è degna di nascondersi. – mostruash