Domanda

Sto cercando di creare un Enum che ha un'etichetta di stringa e un valore e ho intenzione di usare questa roba per leggere da un file ini.

Ad esempio nel file ini che potrebbe avere qualche double, int o string digitare i valori preceduti dal tag / nome del valore:

SomeFloat = 0.5
SomeInteger = 5
FileName = ../Data/xor.csv

Quando ho letto il tag da un file viene in come std::set, quindi mi piacerebbe solo avere EnumType che mantiene tutti i miei valori ... quando ho letto il tag posso solo confrontarlo contro il std::set<EnumType<...>> e se corrisponde l'etichetta allora io controllare il tipo e fare la conversione appropriata (atoi o semplicemente utilizzare la stringa, ecc.)

Ad esempio:

EnumType<int>     someInteger;
someInteger.label = "SomeInteger";
someInteger.type = INT;

std::set<EnumType> myValues;
//
// populate the set
myValues.insert(someInteger);
//

void ProcessTagAndValue(const std::string &tag, const std::string &value)
{
    switch(myValues[tag].type)
    {
    case INT:
        myValues[tag].value = atoi(value);
        break;
    case DOUBLE:
        //
        break;
    case STRING:
        myValues[tag].value = value;
        break;
    default:
        break;
    }
}

enum ValueType{INT,DOUBLE,STRING];

template <class T>
struct EnumType{
    std::string label;
    ValueType   type;
    T           value;

    bool operator==(const EnumType &other) const {
        return this->label == other.label;
    }

    bool operator==(const T& other ) const
    {
        return this->value == other;
    }

    T& operator=(const T& p)
    {
        value = p;
        return value;
    }

    EnumType& operator=(const EnumType& p)
    {
        if (this != &p) {  // make sure not same object
            this->label = p.label;
            this->value = p.value;
        }
        return *this;
    }
};

Ho molte domande:

  1. Può voi dirmi eventuali soluzioni migliori? Non sono sicuro se sto cercando di essere troppo intelligente per il mio bene, o se questo è davvero una soluzione praticabile.

  2. Se la mia soluzione è accettabile, allora nessuno può dirmi come posso dichiarare un insieme di <=> in modo che possa accettare qualsiasi tipo (int, double, string) senza di me in realtà sapere quale tipo enum è intenzione di utilizzare per il valore?

Se avete qualsiasi codice, allora sarebbe grande! :)

È stato utile?

Soluzione

Se si hanno limitato e insieme molto stabile di tipi, quindi Boost.Variant possono essere utilizzati. Se hai intenzione di aggiungere il supporto per nuovi tipi tardi, allora meglio dimenticare questo metodo. In questa soluzione situazione, sulla base di Boost.Any , o un paio di stringhe sarà migliore.

typedef boost::variant<int, double, std::string> ValueType;
struct EnumType {
std::string label;
ValueType value;
};

Un'altra domanda è: "Come questi valori verranno utilizzati in seguito?" Se avete intenzione di passare "SomeInteger" per la funzione, accettando int, si devono ancora eseguire codice simile a:

acceptInt( get<int>( v.value ) ); // get may throw

Questo approccio funziona meglio quando si dispone di un'elaborazione unitaria insieme fisso di tipi:

class processValue : public boost::static_visitor<>
{
public:
    void operator()(int i) const
    {
        acceptInt( i );
    }
    void operator()(double d) const
    {
        acceptDouble( d );
    }
    void operator()(const std::string & str) const
    {
        acceptString( str );
    }
};
boost::apply_visitor( processValue(), v.value );

Altri suggerimenti

Hai guardato Boost.Any ? Si dovrebbe fare quello che vuoi (e se necessità per rotolare il proprio, si può sbirciare alla fonte per i suggerimenti).

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