map mit struct und variant



  • Moin zusammen!

    Folgenden Code habe ich:

    
    #include <variant>
    #include <string>
    #include <map>
    #include <iostream>
    
    struct sbasic{
    	unsigned short int length; // laenge
    	unsigned short int width; // breite
    	unsigned short int height; // hoehe
    	unsigned short int type; // art 
    	unsigned long long int x; // Position
    	unsigned long long int y; // Position
    	unsigned long long int z; // Position
    };
    
    //zuladung
    struct spayload{
    	unsigned short int type; // art 
    };
    
    //zuladung menge
    struct spayloadamount{
    	unsigned short int type[64]; // art
    	unsigned short int amount[64]; // menge an zuladung
    };
    
    int main(int argc, char *argv[]) {
    
    	std::map<sbasic, std::variant<spayload,spayloadamount>> mm;
    
    	mm.insert ( std::pair<unsigned short int,unsigned short int,unsigned short int,unsigned short int,unsigned long long int,unsigned long long int,unsigned long long int>(100,100,100,100,100,100,100) )
    
    	return 0;
    
    }
    
    

    Mein Ziel ist es, eine map zu erstellen mit variablen Inhalt.
    Soll heißen, je nachdem welchen Wert die Variable "type" in "sbasic" hat, möchte ich die beiden anderen struct Strukturen mit einbeziehen.

    Leider bekomme ich jetzt schon folgende Fehlermeldung:

    [Error] wrong number of template arguments (7, should be 2)

    Auch wenn ich nur 2 Argumente habe, wird das Kompilieren mit Fehlern abgebrochen.

    Könnt ihr mir bitte weiter helfen?

    Vielen Dank im Voraus.



  • @no_name1991 Nur kurz vom Handy:
    So funktioniert das mit Maps und Pairs nicht.
    Ein pair ist ein Tuple aus genau zwei Typen.
    Eine Map ist ein Container von einem Pair Typen. Die Doku redet dabei von "key value Pairs". Dabei ist wichtig, dass der Key Teil Vergleichbar ist. Wenn der Typ nicht einfach vergleichbar ist, musst du das selbst definieren und implementieren.



  • @Schlangenmensch sagte in map mit struct und variant:

    Vergleichbar

    Genauer gesagt, sollte es einen Comperator und Hasher geben, je nachdem, welche Map Implementierung man wählt (unordered_map ist die schnellste)...

    (Auch ich schreibe gerade vom Handy, man möge daher Rechtschreibfehler bitte billigen...)



  • @dubios Hier im Post nutzt der TE eine std::map und keine std::unordered_map. Die std::map hat keinen Hasher.


  • Mod

    Die Problemstellung ist also, dass Du eine polymorphe Map haben willst, deren value type von dem Wert des keys abhängt.

    Das ist ein bereits gelöstes Problem mit vielen Lösungswegen:

    1. map value kann einfach ein variant werden, den Du dann manuell entsprechend dem type initialisierst
    2. Du kannst einen polymorphen Map container benutzen, entweder mit vollwertiger type erasure oder variants, siehe e.g. Boost PolyCollection und aehnliches
    3. Du machst die Klassen spayloadamount etc. selbst polymorph mit einer Basisklasse, die dann zum map value wird

    Pauschal ist 3. fuer mich am saubersten, in diesem Fall scheint es eine Art composite pattern zu sein, musst Du aber selbst entscheiden.



  • @Schlangenmensch sagte in map mit struct und variant:

    eine std::map und keine std::unordered_map

    ich sage doch, je nachdem, welche Map man will. eine std::map ist selten die sinnvollste Wahl.



  • @no_name1991 Ich hatte vorhin einen kurzen Schnack mit Copilot... ich glaube, du meintest das so:

    #include <iostream>
    #include <map>
    #include <optional>
    #include <tuple>
    
    struct sbasic
    {
        unsigned short int length; // laenge
        unsigned short int width;  // breite
        unsigned short int height; // hoehe
        unsigned short int type;   // art
        unsigned long long int x;  // Position
        unsigned long long int y;  // Position
        unsigned long long int z;  // Position
    
        bool operator<(const sbasic &other) const
        {
            return std::tie(length, width, height, type, x, y, z) < std::tie(other.length, other.width, other.height, other.type, other.x, other.y, other.z);
        }
    };
    
    // zuladung
    struct spayload
    {
        unsigned short int type; // art
    
        bool operator<(const spayload &other) const
        {
            return type < other.type;
        }
    };
    
    // zuladung menge
    struct spayloadamount
    {
        unsigned short int type[64];   // art
        unsigned short int amount[64]; // menge an zuladung
    };
    
    int main(int argc, char *argv[])
    {
        std::map<spayload, std::map<sbasic, std::optional<spayloadamount>>> m;
    
        m.insert(std::make_pair(spayload{1}, std::map<sbasic, std::optional<spayloadamount>>{}));
        m.insert(std::make_pair(spayload{2}, std::map<sbasic, std::optional<spayloadamount>>{}));
        m[spayload{1}].insert(std::make_pair(sbasic{10, 20, 30, 1, 100, 200, 300}, spayloadamount{{1, 2}, {10, 20}}));
        m[spayload{1}].insert(std::make_pair(sbasic{15, 25, 35, 2, 150, 250, 350}, spayloadamount{{3, 4}, {30, 40}}));
        m[spayload{2}].insert(std::make_pair(sbasic{20, 30, 40, 3, 200, 300, 400}, std::nullopt));
        m[spayload{2}].insert(std::make_pair(sbasic{25, 35, 45, 4, 250, 350, 450}, std::nullopt));
    
        for (const auto &[payload, basicMap] : m)
        {
            std::cout << "Payload Type: " << payload.type << std::endl;
            for (const auto &[basic, payloadAmountOpt] : basicMap)
            {
                std::cout << "  Basic: Length=" << basic.length
                          << ", Width=" << basic.width
                          << ", Height=" << basic.height
                          << ", Type=" << basic.type
                          << ", Position=(" << basic.x << ", " << basic.y << ", " << basic.z << ")"
                          << std::endl;
    
                if (payloadAmountOpt)
                {
                    const auto &payloadAmount = *payloadAmountOpt;
                    std::cout << "    Payload Amounts:" << std::endl;
                    for (size_t i = 0; i < 64; ++i)
                    {
                        if (payloadAmount.type[i] != 0)
                        { // Assuming type 0 means no payload
                            std::cout << "      Type: " << payloadAmount.type[i]
                                      << ", Amount: " << payloadAmount.amount[i]
                                      << std::endl;
                        }
                    }
                }
                else
                {
                    std::cout << "    No payload amount available." << std::endl;
                }
            }
        }
    
        return 0;
    }
    

    Also eine Map, die wieder eine Map hält - anstatt das Variant-Gedengele...