Al momento ho una gerarchia di classi comeC++ implicito modello di istanza
MatrixBase -> DenseMatrix
-> (other types of matrices)
-> MatrixView -> TransposeView
-> DiagonalView
-> (other specialized views of matrices)
MatrixBase
è una classe astratta che costringe gli implementatori di definire operator() (int, int) e cose del genere; rappresenta 2 matrici dimensionali di numeri. MatrixView
rappresenta un modo (possibilmente mutevole) di guardare una matrice, come trasponendola o prendendo una sottomatrice. Il punto di MatrixView
è quello di essere in grado di dire qualcosa di simile
Scale(Diagonal(A), 2.0)
dove Diagonal
restituisce un oggetto DiagonalView
che è una sorta di adattatore leggero.
Ora ecco la domanda (s). Userò un'operazione di matrice molto semplice come esempio. Voglio definire una funzione come
template <class T>
void Scale(MatrixBase<T> &A, const T &scale_factor);
che fa la cosa ovvia che suggerisce il nome. Voglio essere in grado di passare in una matrice non view onestamente buona o in un'istanza di una sottoclasse di MatrixView
. Il prototipo, come scritto sopra non funziona per affermazioni come
Scale(Diagonal(A), 2.0);
perché l'oggetto restituito da DiagonalView
Diagonal
è una temporanea e Scale
prende un riferimento non-const, che non può accettare una temporanea. C'è un modo per farlo funzionare? Ho provato a usare SFINAE, ma non lo capisco molto bene, e non sono sicuro che ciò risolva il problema. Per me è importante che queste funzioni basate su modelli possano essere chiamate senza fornire un elenco di argomenti template esplicito (voglio istanziazione implicita). Idealmente la dichiarazione di cui sopra potrebbe funzionare come scritto.
Edit: (domanda followup)
Come SBI ha risposto di seguito sui riferimenti rvalue e provvisori, C'è un modo per definire due versioni di Scala, uno che prende un riferimento rvalue non-const per non-view e uno che ha una visualizzazione pass-by-value? Il problema è di distinguere tra questi due al momento della compilazione in modo tale che l'istanziazione implicita funzioni.
Aggiornamento
ho cambiato la gerarchia delle classi per
ReadableMatrix
WritableMatrix : public ReadableMatrix
WritableMatrixView
DenseMatrix : public WritableMatrix
DiagonalView : public WritableMatrixView
La ragione WritableMatrixView
è distinto da WritableMatrix
è che la visione deve essere passato in giro per riferimento const, mentre il le matrici stesse devono essere passate da non-const ref, quindi le funzioni dei membri di accesso hanno costanti diverse. Ora funzioni come Scala possono essere definiti come
template <class T>
void Scale(const WritableMatrixView<T> &A, const T &scale_factor);
template <class T>
void Scale(WritableMatrix<T> &A, const T &scale_factor){
Scale(WritableMatrixViewAdapter<T>(A), scale_factor);
}
Nota che ci sono due versioni, una per una vista const, e una versione non-const per le matrici reali. Questo significa che per funzioni come Mult(A, B, C)
, avrò bisogno di 8 sovraccarichi, ma almeno funziona. Ciò che non funziona, tuttavia, sta usando queste funzioni all'interno di altre funzioni.Vedete, ogni classe View
-like contiene un membro View
di ciò che sta guardando; ad esempio nell'espressione Diagonal(SubMatrix(A))
, la funzione Diagonal
restituisce un oggetto di tipo DiagonalView<SubMatrixView<T> >
, che deve conoscere il tipo completamente derivato di A
. Ora, supponiamo che all'interno di Scale
io chiamo qualche altra funzione come questa, che richiede una vista di base o un riferimento di matrice. Ciò fallirebbe perché la costruzione del necessario View
richiede il tipo derivato dell'argomento di Scala; informazioni che non ha. Sto ancora lavorando per trovare una soluzione a questo.
Aggiornamento
ho usato ciò che è effettivamente una versione home-grown di enable_if di Boost di scegliere tra due diverse versioni di una funzione come Scale
. Si riduce all'etichettatura di tutte le mie matrici e visualizza le classi con tag typedef aggiuntivi che indicano se sono leggibili e scrivibili e visualizza o non visualizza. Alla fine, ho ancora bisogno di 2^N overload, ma ora N è solo il numero di argomenti non-const. Per il risultato finale, vedere lo here (è improbabile che venga seriamente rinnovato).
un motivo particolare per cui Scale() non accetta parametri per riferimento const? – Naveen
La scala deve effettivamente ridimensionare il suo argomento, quindi non può essere const. –
Perché la scala modifica la matrice temporanea? –