(Re)denominato std::pair membri

Invece di scrivere town->first vorrei scrivere town->name. Inline denominato funzioni di accesso (Ridenominazione di primo e secondo di un iteratore mappa e Nome std::pair membri) sono le soluzioni migliori che ho trovato finora. Il mio problema con il nome di funzioni di accesso è la perdita di sicurezza del tipo:
pair<int,double> può fare riferimento a struct { int index; double value; } o struct { int population; double avg_temp; }. Chiunque può proporre un approccio semplice, forse qualcosa di simile per caratteristiche?

Spesso vuole il ritorno di una coppia o di una tupla da una funzione ed è molto faticoso, per introdurre un nuovo tipo come struct city { string name; int zipcode; } e la sua ctor ogni volta. Io sono entusiasti di conoscere boost e C++0x, ma ho bisogno di un puro C++03 soluzione senza boost.

Aggiornamento

Re andrewdski domanda: sì, un (ipotetico) sintassi come pair<int=index, double=value> che avrebbe creato un tipo distinto da pair<int=population, double=avg_temp> sarebbe soddisfare le vostre esigenze. Non ho neanche idea di dover implementare una coppia personalizzato/tupla modello di classe una VOLTA e solo di passaggio un ‘nome tratti modello argomento è approprietly quando ho bisogno di un nuovo tipo. Non ho idea di come che ‘nome tratti sarebbe simile. Forse è impossibile.

  • Come non è, questo, un problema reale? Perché il downvote?
  • Vorrei sapere anche questo.
  • Il downvote è il pensiero che ogni oggetto con due membri dovrebbero ereditare da std::pair e rinominare i membri. Non abbiamo bisogno di std::tripla e std::quad per i più grandi oggetti?!
  • Persson: si dovrebbe leggere la domanda prima di downvoting: dove mi ha fatto ricordare ereditarietà?
  • Persson C’è std::tupla / boost::tupla per oggetti più grandi.
  • Forse il problema è che la gente non riesce a capire cosa stai chiedendo. Tu dici di voler distinguere tra struct { int index; double value; } e struct { int population; double avg_temp; }, ma si vuole fare questo semplicemente rinominando coppia membri? Come in tutto il mondo come vorrei che lavoro? Sembra certo, come si desidera una struct. (E per la cronaca, io non downvote.)
  • Sì, vedi che il mio problema in modo corretto. Vorrei riutilizzare std::pair, e rinominare i suoi membri, in QUALCHE modo. Se sapevo la risposta come, non vorrei fare questa domanda. 🙂
  • Ma questi sono per i tipi con unnamed membri.
  • Questo potrebbe essere un lavoro per le macro per creare le strutture di cui avete bisogno, se si vuole risparmiare un po ‘ di digitare ogni volta
  • Come, altrimenti, sarebbero i tipi di ottenere i membri di una coppia?
  • Persson sono d’accordo – che eredita da std::pair o tutto ciò che è stupido. Volevo solo dire perché non abbiamo bisogno di un std::tripla e std::quad.
  • Così un (ipotetico) sintassi come pair<int=index, double=value> che avrebbe creato un tipo distinto da pair<int=population, double=avg_temp> sarebbe soddisfare le vostre esigenze?
  • Downvoting senza commento è giustificata dal fatto che qualcuno non capisce qualcosa o è un malinteso? È necessario disporre di downvoted ogni domanda, allora. (Da notare che non ha mai detto nulla sull’ereditarietà comunque, io non sono abbastanza sicuro di quello che è.)
  • Ho downvoted durante i 30 minuti prima ha curato la domanda. Era solo per non comprensibile. Come si fa a modificare una classe senza ereditare da essa?!
  • Persson: non ho mai parlato di ereditarietà, è possibile controllare facilmente la storia. Da tratti, è possibile collegare le informazioni per classi, senza modificarle. Non so come funzionerebbe in questo caso, per cui la questione.
  • Sì. Non ho neanche idea di dover implementare una coppia personalizzato/tupla modello di classe una VOLTA e solo di passaggio a nome dei tratti a approprietly in ogni caso ho bisogno di un nuovo tipo. Tuttavia, il riutilizzo di std::pair è preferito.
  • Non è possibile modificare i nomi dei membri con tratti, si può? E non è possibile modificare un classe’ comportamento senza la eredita e l’override delle funzioni virtuali. Ho appena trovato la prima domanda davvero stupida a causa di questo, ma ovviamente le persone non sono d’accordo.
  • Persson: per la domanda originale, da dove scrivo di modifica di comportamento?
  • Hmmm sembra che ho perso la parte in cui hai detto che non vuoi impiegare boost 🙂 in questo caso @dalle risposta dovrebbe essere ok (a parte le ‘basta usare una struct con il coro, che è a destra, ma noioso)

InformationsquelleAutor Ali | 2011-05-21



9 Replies
  1. 18

    Non vedo come si possa fare di meglio

    struct city { string name; int zipcode; };

    Non c’è niente di non-essenziale non c’. Hai bisogno di tipi, di due membri, di tutta la tua domanda è basata intorno a dare il nome alle due membri, e si desidera essere un tipo unico.

    Fare conoscere la sintassi di inizializzazione aggregata, giusto? Non hai bisogno di un costruttore o di un distruttore, il compilatore fornito quelli che vanno più che bene.

    Esempio: http://ideone.com/IPCuw


    Tipo di sicurezza richiede l’introduzione di nuovi tipi, altrimenti pair<string, int> è ambiguo tra (nome, il codice postale) e (popolazione, temp).

    In C++03, la restituzione di una nuova tupla richiede:

    city retval = { "name", zipcode };
    return retval;

    o la scrittura di una comodità costruttore:

    city::city( std::string newName, int newZip ) : name(newName), zipcode(newZip) {}

    per ottenere

    return city("name", zipcode);

    Con il C++0x, tuttavia, vi sarà permesso di scrivere

    return { "name", zipcode };

    e nessun utente-definito costruttore è necessario.

    • Si mi ha battuto. Devo aggiungere però che con string l’inizializzazione aggregata sintassi non funziona.
    • potrebbe essere buono per espandere la sintassi di inizializzazione aggregata per il grande pubblico di google
    • Dice che? È funziona bene per me.
    • Non sapevo che lavorato con std::string all’interno. Gcc accetta con -ansi. Si prega di non prendere il mio primo commento in conto.
    • Sarebbe abbastanza problematico se questo non era permesso: inizializzazione di matrice usa lo stesso di aggregazione inizializzatore.
    • Voigt: con voto positivo e grazie. Purtroppo estesa lista di inizializzazione non è disponibile in C++03, non è possibile scrivere return { "new york", 10001 }; alla fine di una funzione. Quindi è ancora necessario scrivere un costruttore e scrivere return city("new york", 10001);. Ho bisogno di un puro C++03 soluzione.
    • Cosa c’è di sbagliato con city retval = { "new york", 10001 }; return retval; ? Dopo “Denominato Valore di Ottimizzazione di Ritorno”, che praticamente tutti i moderni compilatori, sarà la stessa.
    • Voigt: in Parte la mia mancanza di conoscenza. 🙂 D’altra parte, avrei preferito scrivere un costruttore, una volta di scrivere una riga ogni volta che una città è tornato. C++0x risolvere questo problema. Grazie!
    • Voigt: vorrei accettare la tua risposta, ma si prega di aggiungere le seguenti: ad esso. (1) È necessario introdurre nuove tipologie altrimenti non si può avere sia typedef pair<string /*name*/,int /*zipcode*/> city; e typedef pair<string /*street*/,int /*number*/> building; (2) In C++0x si sarà in grado di scrivere return { "new york", 10001 }; (3) Nel frattempo si sia scrivere un costruttore o una o l’aggiunta di un’ulteriore linea di city retval = { "new york", 10001 }; return retval; ogni volta che una città è tornato. Grazie!
    • Il link per ideone è morto e non è disponibile su internet archive – sai che a una sostituzione?
    • No, è un peccato che ideone del ToS dichiarare che è un luogo per pubblicare i frammenti di codice sorgente “per Sempre”, ma in realtà distruggono proprietà dell’utente materiale e non rispondono a richieste di informazioni. Ho praticamente smesso di usare per questa ragione.
    • ok, grazie per le verifiche.
    • Scusa per il ritardo della risposta, ma hai avuto questo problema con coliru a tutti? Che è quello che io principalmente uso per il live esempi.

  2. 5

    Anche se non perfetto, è possibile utilizzare i tag di dati:

    template <typename tag_type, typename pair_type>
    typename tag_type::type& get(pair_type& p);
    
    typedef std::pair<std::string /*name*/, int /*zipcode*/> city;
    struct name { typedef std::string type; };
    struct zipcode { typedef int type; };
    
    template <>
    std::string& get<name, city>(city& city)
    {
       return city.first;
    }
    
    template <>
    int& get<zipcode, city>(city& city)
    {
       return city.second;
    }
    
    int main()
    {
       city c("new york", 10001);
       std::string n = get<name>(c);
       int z = get<zipcode>(c);
    }

    Ma come Ben Voigt dice: struct city { string name; int zipcode; }; sarebbe praticamente sempre essere migliore.

    EDIT: Modelli sono probabilmente eccessivo, si potrebbe utilizzare la connessione funzioni in uno spazio dei nomi, invece. Questo ancora non risolve il tipo di problemi di sicurezza, come qualsiasi std::pair<T1, T2> dello stesso tipo di quella di qualsiasi altro std::pair<T1, T2>:

    namespace city
    {
       typedef std::pair<std::string /*name*/, int /*zipcode*/> type;
    
       std::string& name(type& city)
       {
          return city.first;
       }
    
       int& zipcode(type& city)
       {
          return city.second;
       }
    }
    
    int main()
    {
       city::type c("new york", 10001);
       std::string n = city::name(c);
       int z = city::zipcode(c);
    }
    • Dovra ‘ upvote questo… è proprio quello che il mio suggerimento (boost::bimaps) non
    • Grazie per i vostri sforzi per rispondere alla mia domanda. Comunque io ancora non capisco. Perché avete quelle typedef nelle strutture? Essi sembrano essere inutilizzati. E il tipo di sicurezza problema non viene risolto, è possibile avere un altro typedef std::pair<std::string /*street*/, int /*number*/> building;. Che era il mio problema con il nome di funzioni di accesso.
    • Tutti std::pair<T1, T2> dello stesso tipo di quella di qualsiasi altro std::pair<T1, T2>. Se si desidera che il tipo di sicurezza è necessario utilizzare diversi tipi.
    • Sì, lo so. Non ho neanche idea di dover implementare una coppia personalizzato/tupla modello di classe una VOLTA e solo di passaggio un ‘nome tratti modello argomento è approprietly quando ho bisogno di un nuovo tipo. Non ho idea di come che ‘nome tratti sarebbe simile. Forse è impossibile. Vuoi vedere ciò che vorrei avere?
    • con voto positivo la tua risposta e grazie. Forse un semplice struct city { string name; int zipcode; }; è davvero la soluzione più semplice, e con il C++0x sarò in grado di utilizzare l’inizializzazione aggregata.
  3. 3

    Dal std::pair è comunemente utilizzato per la memorizzazione di voci std::map contenitori, si potrebbe desiderare di guardare tagged elementi Boost Bimap.

    Sinossi:

    #include <boost/bimap/bimap.hpp>
    #include <string>
    #include <iostream>
    
    struct name {}; //Tag for the default 'first' member
    struct zipcode {}; //Tag for the default 'second' member
    
    int main()
    {
        using namespace boost::bimaps;
        typedef bimap <tagged<std::string, name>, tagged<int, zipcode> > Cities;
        typedef Cities::value_type registration;
    
        Cities cities;
        cities.insert(registration("Amsterdam", 20));
        cities.insert(registration("Rotterdam", 10));
    
        //...
        std::string cityName;
        std::cin >> cityName;
    
        Cities::map_by<name>::const_iterator id_iter = cities.by<name>().find(cityName);
        if( id_iter != cities.by<name>().end() )
        {
            std::cout << "name: " << id_iter->get<name>() << std::endl
                      << "zip: " << id_iter->get<zipcode>()   << std::endl;
        }
    
        return 0;
    }

    Nota che bimaps in modo trasparente possono emulare std::map o altri associativo tipi di contenitore senza costo delle prestazioni; solo Che sono più flessibili. In questo particolare esempio, la definizione sarebbe più probabile essere cambiato in qualcosa di simile:

    typedef bimap <tagged<std::string, name>, multiset_of<tagged<int, zipcode> > > Cities;
    typedef Cities::value_type registration;
    
    Cities cities;
    cities.insert(registration("Amsterdam", 20));
    cities.insert(registration("Rotterdam", 10));
    cities.insert(registration("Rotterdam", 11));

    Vi invito a passeggiare per la documentazione per Aumentare Bimap per avere il quadro completo

    • Grazie per la tua risposta. Sono felice di imparare di più su di spinta. Si prega di vedere il mio commento sehe la risposta, ho dei problemi di comprensione.
  4. 3

    Credo elaborando

    struct City : public std::pair<string, int> {
      string& name() { return first; }
      const string& name() const { return first; }
      int& zip() { return second; }
      int zip() const { return second; }
    };

    è il più vicino si arriva a quello che stai cercando, althrough struct City { string name; int zipcode; } sembra perfettamente bene.

    • citando la domanda: Inline denominato funzioni di accesso (1, 2) sono le soluzioni migliori che ho trovato finora
  5. 2

    Sarete felici di sapere che gli intervalli proposta include anche un qualcosa che si chiama tagged_pair, in modo che la vostra:

    struct city { string name; int zipcode; };

    può anche essere scritto come:

    using city = tagged_pair<tag::name(std::string), tag::zipcode(int)>;
    
    city c{"Chicago", 60654};
    std::cout << c.name() << " is at zipcode " << c.zipcode() << '\n';

    Naturalmente, questo può essere utilizzato anche nel tipo di ritorno direttamente come normale:

    tagged_pair<tag::min(int), tag::max(int)> get_range() {
         return {0, 100};
    }
    
    auto score_range = get_range();
    std::cout << "From " << score_range.min() << " to " << score_range.max();
  6. 1

    È possibile utilizzare il puntatore-a-membro operatori. Ci sono un paio di alternative. Qui è il più semplice.

    typedef std::map< zipcode_t, std::string > zipmap_t;
    static zipcode_t const (zipmap_t::value_type::*const zipcode)
                                                  = &zipmap_t::value_type::first;
    static std::string (zipmap_t::value_type::*const zipname)
                                                  = &zipmap_t::value_type::second;
    
    //Usage
    zipmap_t::value_type my_map_value;
    std::string &name = my_map_value.*zipname;

    Si può mettere le funzioni di accesso per uno pseudo-tipo, in un apposito namespace che li separa da altre cose. Quindi, sarebbe simile a my_map_value.*zip::name. Ma, a meno che non si ha realmente bisogno di utilizzare un pair, probabilmente è più facile, basta definire una nuova struct.

    • Sì, credo che il codice è il più facile da capire se si definisce una nuova struttura. Se devo usare coppie, io uso inline funzioni di accesso. Comunque, grazie per la risposta, con voto positivo!
  7. 1

    Mi si avvicinò con un Utility_pair macro che può essere utilizzata come questo:

    Utility_pair(ValidityDateRange,
        time_t, startDay,
        time_t, endDay
    );

    Quindi, ogni volta che è necessario per accedere ai campi di ValidityDateRange, si può fare come questo:

    ValidityDateRange r = getTheRangeFromSomewhere();
    
    auto start = r.startDay(); //get the start day
    r.endDay() = aNewDay();    //set the end day
    r.startDay(aNewDay1())     //set the start and end day in one go.
     .endDay(aNewDay2());

    Questo è l’implementazione:

    #include <utility>
    
    #define Utility_pair_member_(pairName, ordinality, type, name)      \
        const type &name() const { return ordinality; }                 \
        type &name() { return ordinality; }                             \
        pairName &name(const type &m) { ordinality = m; return *this; } \
    /***/
    
    #define Utility_pair(pairName, firstMemberType, firstMemberName, secondMemberType, secondMemberName) \
        struct pairName: std::pair<firstMemberType, secondMemberType>  {                                 \
            Utility_pair_member_(pairName, first, firstMemberType, firstMemberName)                      \
            Utility_pair_member_(pairName, second, secondMemberType, secondMemberName)                   \
        }                                                                                                \
    /***/
  8. 0

    Penso che si dovrebbe davvero introdurre nuovi tipi qui. Io sono totalmente su stl in termini di avere una coppia di classe, ma questo è l’esatto motivo per cui java persone sostengono che non vuole avere un paio di classe e si dovrebbe sempre introdurre nuovi tipi per la vostra piar-come tipi.

    La buona cosa circa il stl soluzione è che si può usare il generico classe di coppia, ma è possibile introdurre nuovi tipi di classi di ogni volta che si vuole veramente i membri a essere chiamato in modo diverso da prima/seconda. In cima a che l’introduzione di nuove classi ti dà la libertà di facilmente aggiungere un terzo membro, se dovesse essere necessario.

  9. -1

    forse si può ereditare il tuo paio di classe in coppia e set di due riferimenti chiamato il nome e il codice postale nel costruttore ( basta essere sicuri di implementare tutti i costruttori si usa )

    • std::pair non sono un distruttore virtuale, quindi questo potrebbe portare ad accidentali perdite di memoria.
    • Grazie. Ma se si introduce un nuovo tipo, perché non introdurre struct città, {string nome; int cap; } in primo luogo?
    • sì, si dovrebbe dichiarare il proprio distruttori (che sarà chiamata genitore distruttori) così come i costruttori @Ali: ereditando dalla coppia, è possibile utilizzare tutte le sue funzionalità ( per esempio quando una funzione predefinita esigenze coppia come argomento, compilatore uso automatico il vostro tipo di coppia se si utilizza il ownPair ereditato dalla coppia )
    • Non è questo il problema. Se nulla viene aggiunto alla classe che prevede la distruzione, quei distruttori non essere chiamato da qualsiasi cosa che richiede solo un std::pair codersource.net/c/c-miscellaneous/c-virtual-destructors.aspx

Lascia un commento