Templateparameter wiederholen



  • Hallo,

    ich erzeuge in einer Funktion eine map<int, float> . Nun möchte ich in dem Code sicherstellen, dass ich, wenn ich später die Map vielleicht in map<long, double> ändere, keine weiteren Anpassungen vornehmen muss.

    Die Keys und Values werden aus einer Datei gelesen.

    Nun dachte ich, dass ich folgendes mache:

    map<int, float> foo() {
        map<int, float> result;
        ...
        pair<int, float> p;
        while (infile >> p.first >> p.second) {
            // do some work & error checking
            auto success = result.insert(p).second;
            // check success
        }
        return result;
    }
    

    Jetzt habe ich allerdings das <int, float> 3x wiederholt!

    Erste Idee zum Paar: decltype(result)::value_type p; nehmen. Nur logischerweise funktioniert das nicht, weil der Key const ist. Eine Lösung ist:

    pair<remove_const<decltype(result)::value_type::first_type>::type,
        decltype(result)::value_type::second_type> p;
    

    Das sieht mir aber doch etwas unübersichtlich aus (wird auch durch remove_const_t nicht wirklich besser). Würdet ihr das so machen oder doch einfach pair<int,float> schreiben und die Typen damit wiederholen? Die Funktion ist jetzt nicht sooo lang, dass das ein Problem wäre. Dennoch: irgendwie finde ich das unschön so.

    Gut, nächstes Problem: ich könnte das Paar zu zwei einzelnen Variablen manchen. Dann hätte ich ordentliche Namen. Aber dann hat man eine int-Variable und eine float-Variable und sieht weniger, dass hier derselbe Typ wie um Returntyp stehen sollte... Wie ist es am besten?



  • using Map = map<int, float>;
    using Pair = pair<Map::key_type, Map::mapped_type>;
    
    Map foo() {
        Map result;
        Pair  p;
        while (infile >> p.first >> p.second) {
            // do some work & error checking
            auto success = result.insert(p).second;
            // check success
        }
        return result;
    }
    


  • manni66 schrieb:

    using Map = map<int, float>;
    using Pair = pair<Map::key_type, Map::mapped_type>;
    

    👍

    Meine Güte, einfach dem ganzen mal von außen einen Namen geben! Das hätte mir auch einfallen können (vor allem, weil ich Programmieren mit Turbo Pascal angefangen habe, wo man sowas ja machen musste)!



  • Warum nicht dieses?

    template <typename K, typename V>
    std::map<K, V> foo()
    {
        std::map<K, V> result;
        std::pair<K, V> p;
        while (infile >> p.first >> p.second)
            result.insert(p);
        return result;
    }
    


  • Irgendwie finde ich das zu generisch. Ich habe bestimmte Anforderungen an das "V", es sind nämlich hier nur bestimmte Werte erlaubt bzw. bestimmte Wertekombinationen. Einfache Checks mache ich gerne schon so früh wie möglich. Mir fehlt dann z.B., dass V eine Zahl ist. Gut, dann könnte man noch ein static_assert(is_arithmetic<V>::value, "") oder so einbauen. Aber wahrscheinlich wäre einer von float, double, int sogar richtiger.

    Und außerdem ist Code ohne Templates deutlich einfacher zu lesen.

    Manni66s Idee ist schon gut, dann bekommt die Map nämlich auch einen vernünftigen Namen. Wenn man jetzt noch "first" und "second" umbenennen könnte...


  • Mod

    wob schrieb:

    Manni66s Idee ist schon gut, dann bekommt die Map nämlich auch einen vernünftigen Namen. Wenn man jetzt noch "first" und "second" umbenennen könnte...

    template typename<K, V> struct MyMap: public map<K, V>
    {
      using first = K;
      using second = V;
    };
    


  • Sorry, verstehe ich nicht, was du mir sagen willst bzw. wie ich das einsetzen kann.

    Using macht doch nur einen Alias für einen Typen, aber beim Umbenennen von first und second brauche ich doch einen Alias für eine Variable oder nicht? D.h. meine map müsste einen Custom-Pair-Typ haben?!

    Außerdem kompiliert dein Code nicht.

    error: expected nested-name-specifier before ‘<’ token
     template typename <K, V> struct MyMap: public map<K, V>
                       ^
    

    Meintest du sowas:

    template <typename K, typename V>  struct MyPair : public pair<K, V> {
    

    Aber auch da weiß ich nicht, wie ich das sinnvoll einsetzen sollte.

    Aber wie gesagt, das Ursprungsproblem ist gelöst.


  • Mod

    Oh, jetzt verstehe ich. Ich dachte, du wolltest Map::key_type bzw. Map::mapped_type aus mannis Code zu first bzw. second umbenennen.


Log in to reply