2014-09-12 5 views
13

Ho scritto un piccolo programma di utilizzo di std :: map qui come segue.come interrompere la conversione automatica da int a float e viceversa in std :: map

int main() 
{ 
    map<int,float>m1; 
    m1.insert(pair<int,float>(10,15.0)); //step-1 
    m1.insert(pair<float,int>(12.0,13)); //step-2 
    cout<<"map size="<<m1.size()<<endl; //step -3 

ho creato una mappa con tipo int come chiave e float tipo valore (valore-chiave) coppia per la mappa m1

passo-1 creato un normale paio int flottante ed inserito alla mappa.

step-2 Creata una coppia cross float-int e inserita per mappare. Ora so che la conversione implicita sta facendo inserire questa coppia nella mappa.

Qui semplicemente non voglio che la conversione implicita avvenga e si dovrebbe dare l'errore del compilatore.

Che tipo di modifiche devo fare in questo programma/mappa per far sì che il comigeratore contrassegni un errore mentre proviamo a eseguire un'operazione di tipo step-2?

Grazie in anticipo.

risposta

6

Ecco un suggerimento:

template <typename K, typename V, typename W> 
void map_insert(map<K,V>& m, K k, W w) { 
    V v = w; 
    m.insert(pair<K,V>(k,v)); 
} 

int main() { 
    map<int,float>m1; 
    map_insert(m1, 10, 15.0); 
    map_insert(m1, 12.0, 13); // compiler complains here 
    cout<<"map size="<<m1.size()<<endl; 

Il parametro terzo modello è un po 'imbarazzante, ma è necessario per consentire la fusione da double a float.

+0

Puoi approfondire il motivo per cui è necessario il terzo parametro di modello? – Gareth

+0

Senza di esso, il compilatore si lamenta che non può corrispondere ai parametri del modello per la prima chiamata map_insert(), poiché 15.0 è un doppio, non un float. – dshin

+0

Questa è difficilmente una soluzione (o una risposta) al suo problema: è solo un'API completamente diversa che evita di costruire una coppia std :: tutti insieme. Anche se in questo senso avrebbe "funzionato", rientra anche nella categoria banale. –

2

vi possa essere un modo più semplice, ma questo è ciò che è accaduto a me:

#include <iostream> 
#include <map> 

template<typename Key, typename Value> 
struct typesafe_pair 
{ 
    const Key& key; 
    const Value& value; 
    explicit typesafe_pair(const Key& key, const Value& value): key(key), value(value) {} 

    operator typename std::map<Key, Value>::value_type() { return typename std::map<Key, Value>::value_type(key, value); } 
}; 

int main() 
{ 
    std::map<int,float>m1; 

    m1.insert(std::pair<int,float>(10,15.0)); // allowed 
    m1.insert(std::pair<float,int>(12.0,13)); // allowed!! 

    m1.insert(typesafe_pair<int,float>(10, 15.0)); // allowed 
    m1.insert(typesafe_pair<float, int>(12.0, 13)); // compiler error 

    std::cout << "map size=" << m1.size() << std::endl; //step -3 
} 

EDIT: 1 Qualcuno potrebbe essere in grado di fornire una soluzione migliore (più efficiente) che coinvolge i riferimenti rvalue e spedizioni perfetta magia che non riesco ancora a cogliere.

EDIT 2: Penso Carlo legno ha la migliore IMHO soluzione.

3

Questo non è possibile (e anche se è possibile, allora sarebbe importante mod di che non si dovrebbe usare).

insert guadagnato un value_type come argomento, che è un pair<int const,float>. Quindi, quando si tenta di inserire un pair<float, int>, il compilatore cerca una conversione, ovvero: un costruttore di pair<int const, float> che accetta come argomento un pair<float, int>, che esiste semplicemente. In effetti, ho cercato di creare una specializzazione parziale per quel membro del template (che consente la conversione), che quindi potresti avere esito negativo sul restante parametro del template, ma non ci sono riuscito; sembra impossibile. Ad ogni modo, sarebbe un trucco molto sporco che non dovresti fare solo per evitare errori di battitura. Altrove potresti aver bisogno di questa conversione, ed è un no no per definire comunque qualcosa nello spazio dei nomi std.

Quindi qual è la soluzione a "Come posso evitare questo tipo di errori di battitura?" ?

Ecco quello che faccio di solito:

1) Tutte le mie mappe hanno un typedef per il loro tipo.
2) Quindi utilizzo ::value_type (e ::iterator ecc.) Su quel tipo esclusivamente.

Questo non è solo più robusto, è anche più flessibile: è possibile modificare il tipo di contenitore in seguito e il codice è probabile che funzioni ancora.

Quindi, il codice diventerebbe:

int main() 
{ 
    typedef std::map<int,float> m_type; 
    m_type m1; 

    m1.insert(m_type::value_type(10,15.0)); // allowed 
    m1.insert(m_type::value_type(12.0,13)); // no risk for a typo. 

Una soluzione alternativa potrebbe essere quella di avvolgere il vostro float in una classe personalizzata. Questa non è una brutta cosa da fare comunque per (ancora) ragioni di flessibilità. È raro che sia piacevole avere un codice scritto utilizzando lo std::map<int, builtin-type> per rendersi conto che è necessario archiviare più dati e credetemi che succede molto. Si potrebbe anche iniziare con una classe fin dall'inizio.