Domanda

Sto lavorando su un codice che esegue query sul vicino più vicino. Esistono due semplici idee alla base di come un utente potrebbe richiedere dati in una ricerca:

  • N più vicini a un determinato punto nello spazio.
  • tutti i punti entro una determinata distanza.

Nel mio codice, i punti vengono inseriti in una lista punti e la lista punti è un contenitore che ha il compito di tenere traccia dei punti trovati nella ricerca.

In questo momento il mio oggetto PointList ha un costruttore:

PointList( unsigned int maxvals ); // #1

I prossimi due costruttori che vorrei aggiungere sono questi:

PointList( float maxdist ); // #2
PointList( unsigned int maxvals, float maxdist ); // #3

La mia domanda è: come posso garantire che i miei utenti e il compilatore C ++ generino il giusto costruttore per la Lista punti e distingue tra i costruttori 1 e 2? Dovrei solo implementare # 3 e fornire costanti che definiscono arbitrariamente grandi valori per maxvals e maxdist? Un'altra alternativa potrebbe essere quella di scrivere un altro sistema di oggetti leggeri che regolano la logica per l'aggiunta di punti all'elenco, ma sembra eccessivo per un'idea così semplice.

Sto davvero cercando di renderlo trasparente per i miei utenti, che sono per lo più scienziati che a volte hanno imparato il C ++ senza il beneficio dell'istruzione formale. Grazie!

È stato utile?

Soluzione

La risoluzione del sovraccarico per i tipi interi si presenta in due categorie, che possono essere riassunti in modo molto approssimativo in

  • Promozione: si tratta di una conversione da tipi più piccoli di int a unsigned int o float, a seconda che double sia in grado di memorizzare tutti i valori del tipo di origine.
  • Conversione: è una conversione da qualsiasi tipo intero a un altro tipo intero.

Simile, la conversione per i tipi in virgola mobile avviene in due categorie

  • Promozione: si tratta di una conversione da <=> a <=>
  • Conversione: si tratta di una conversione da qualsiasi tipo a virgola mobile a un altro tipo a virgola mobile

E c'è una conversione da intero a mobile o indietro. Questo è classificato come una conversione, piuttosto che una promozione. Una promozione è classificata meglio di una conversione e laddove è necessaria solo una promozione, tale caso sarà preferito. Pertanto, è possibile utilizzare i seguenti costruttori

PointList( int maxVals );
PointList( unsigned int maxVals );
PointList( long maxVals );
PointList( unsigned long maxVals );

PointList( double maxDist );
PointList( long double maxDist );

Per qualsiasi tipo intero, questo dovrebbe selezionare il primo gruppo di costruttore. E per qualsiasi tipo a virgola mobile, questo dovrebbe selezionare il secondo gruppo di costruttori. I tuoi due costruttori originali potrebbero facilmente provocare un'ambiguità tra <=> e <=>, se passi un <=>, per esempio. Per l'altro, costruttore di due argomenti, puoi scegliere la soluzione, se lo desideri.


Detto questo, userei anche una funzione di fabbrica, perché decidere sul tipo il significato del parametro è piuttosto fragile, credo. Molte persone si aspetterebbero che il seguente risultato sia uguale

PointList p(floor(1.5));
PointList u((int)1.5);

Ma provocherebbe un diverso stato delle cose.

Altri suggerimenti

Perché non usare metodi di fabbrica anziché costruttori? I metodi di fabbrica hanno il vantaggio di nomi personalizzabili.


static PointList createNearestValues(unsigned int maxvals) {}
static PointList createByDistance(float maxdist) {}

Prendi in considerazione l'utilizzo di typedefs veri . È un po 'più sforzo da parte del codice client, ma hai la correttezza garantita.

Call PointList (10) per il primo e PointList (10f) per il secondo.

Per il secondo, puoi anche usare 10.0.

Se sono presenti i costruttori n. 1 e n. 2, verrà chiamato il costruttore corretto se il valore inserito è float o int e non deve avvenire alcuna conversione. Quindi assicurati solo di rendere espliciti i tipi dei numeri che usi per chiamare (cioè 1f e 1). Il costruttore n. 3 non sembra essere un'opzione in quanto non è davvero necessario e confonderebbe semplicemente gli utenti del tuo codice. Se hai bisogno di valori predefiniti per entrambi i numeri, puoi utilizzare

PointList(int max, float max=VALUE)

e

PointList(float max, int max=VALUE)

Ancora una volta: questo sembra fare più male del codice in termini di leggibilità del codice.

Ciò richiede una buona lettura su Risoluzione di sovraccarico .

Utilizzerei sicuramente i costruttori espliciti . Nell'esempio, il numero intero senza segno non viene convertito in modo implicito.

class A
{
public:
    explicit A(float f){}
    explicit A(int i){}
};

void test(){
    unsigned int uinteger(0);
    A a1(uinteger);        //Fails, does not allow implicit conversions

    A a2((float)uinteger); //OK, explicit conversion

    float f(0.0);
    A a3(f);               //OK

    int integer(0);
    A a4(integer);         //OK
}

Il messaggio di errore è abbastanza semplice da capire:

: error C2668: 'A::A' : ambiguous call to overloaded function
: could be 'A::A(int)'
: or       'A::A(float)'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top