Domanda

Sto cercando di creare una classe vettoriale "sparsa" in C++, in questo modo:

template<typename V, V Default>
class SparseVector {
    ...
}

Internamente sarà rappresentato da un std::map<int, V> (Dove V è il tipo di valore memorizzato).Se un elemento non è presente nella mappa, faremo finta che sia uguale al valore Default dall'argomento template.

Tuttavia, ho problemi a sovraccaricare l'operatore pedice, [].Devo sovraccaricare il [] operatore, perché sto passando oggetti da questa classe a una funzione Boost che si aspetta [] per funzionare correttamente.

IL const la versione è abbastanza semplice:controlla se l'indice è nella mappa, restituisci il suo valore in tal caso, oppure Default Altrimenti.

Tuttavia, la versione non const mi richiede di restituire un riferimento, ed è qui che mi imbatto in problemi.Se il valore è solo l'essere Leggere, non ho bisogno (né voglio) aggiungere nulla alla mappa;ma se è così scritto, forse devo inserire una nuova voce nella mappa.Il problema è che il sovraccarico [] non sa se l'essere è un valore Leggere O scritto.Restituisce semplicemente un riferimento.

C'è un modo per risolvere questo problema?O forse per aggirare il problema?

È stato utile?

Soluzione

Potrebbe esserci qualche trucco molto semplice, ma penso per il resto operator[] deve solo restituire qualcosa che può essere assegnato da V (e convertito in V), non necessariamente V&.Quindi penso che tu debba restituire qualche oggetto con un sovraccarico operator=(const V&), che crea la voce nel tuo contenitore sparse.

Dovrai però verificare cosa fa la funzione Boost con il suo parametro di modello: una conversione definita dall'utente in V influisce su quali catene di conversione sono possibili, ad esempio impedendo che ci siano altre conversioni definite dall'utente nella stessa catena.

Altri suggerimenti

Non lasciare che l'implementazione dell'operatore non const restituisca un riferimento, ma un oggetto proxy.È quindi possibile implementare l'operatore di assegnazione dell'oggetto proxy per distinguere gli accessi in lettura a operator[] dagli accessi in scrittura.

Ecco alcuni schizzi di codice per illustrare l'idea.Questo approccio non è carino, ma va bene: questo è C++.I programmatori C++ non perdono tempo gareggiando in concorsi di bellezza (nemmeno loro avrebbero alcuna possibilità).;-)

template <typename V, V Default>
ProxyObject SparseVector::operator[]( int i ) {
   // At this point, we don't know whether operator[] was called, so we return
   // a proxy object and defer the decision until later
   return ProxyObject<V, Default>( this, i );
}

template <typename V, V Default>
class ProxyObject {
    ProxyObject( SparseVector<V, Default> *v, int idx );
    ProxyObject<V, Default> &operator=( const V &v ) {
      // If we get here, we know that operator[] was called to perform a write access,
      // so we can insert an item in the vector if needed
    }

    operator V() {
      // If we get here, we know that operator[] was called to perform a read access,
      // so we can simply return the existing object
    }
};

Mi chiedo se questo design sia valido.

Se vuoi restituire un riferimento, significa che i client della classe possono memorizzare il risultato della chiamata operator[] in un riferimento e leggerlo/scriverlo in qualsiasi momento successivo.Se non si restituisce un riferimento e/o non si inserisce un elemento ogni volta che viene indirizzato un indice specifico, come potrebbero farlo?(Inoltre, ho la sensazione che lo standard richieda la fornitura di un contenitore STL adeguato operator[] per fare in modo che l'operatore restituisca un riferimento, ma non ne sono sicuro.)

Potresti essere in grado di aggirarlo fornendo al tuo proxy anche un file operator V&() (che creerebbe la voce e assegnerebbe il valore predefinito), ma non sono sicuro che questo non aprirebbe semplicemente un'altra scappatoia in alcuni casi a cui non avevo ancora pensato.

std::map risolve questo problema specificando che la versione non const di quell'operatore inserisce sempre un elemento (e non fornendo a const versione affatto).

Certo, puoi sempre dirlo non è un contenitore STL standardizzato e operator[] non restituisce riferimenti semplici che gli utenti possono memorizzare.E forse va bene così.Mi chiedo solo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top