[ERLEDIGT] template einschränken



  • Max3000 schrieb:

    Gegenbeispiel:
    Du hast eine allgemeine Funktion, die für alle Typen funktioniert und hast für z.B. 4 Typen eine spezielle Modifikation für diese Funktion, die noch besser/schneller/schöner ist und für die anderen Typen nicht funktioniert.

    ->

    Michael E. schrieb:

    Wenns keine andere Verwendungsmöglichkeit für die Funktion gibt außer für diese drei Typen

    Verwendungsmöglichkeit im Sinne von: Semantisch macht es für andere Typen keinen Sinn, nicht, dass es da eine tollere Implementierung gibt.



  • seldon schrieb:

    Definier haltWie genau du es einbinden musst, kann ich dir nicht sagen, weil ich deinen Code nicht kenne. Du musst dich halt nur auf fwd_type_if_allowed<T>::type beziehen, denn wenn der Compiler das für einen nicht freigeschalteten Typ aufzulösen versucht, hagelt es Compilerfehler - wie ich ja bereits erwähnte.

    Ein wenig abstrahiert:

    std::map<int, UTM> coords;
    std::map<int, Knot> knots;
    std::map<int, Edge> edges;
    std::map<int, Edge> faces;
    
    template<typename> struct fwd_type_if_allowed { };
    
    template<> struct
    fwd_type_if_allowed<UTM> { 
    	typedef std::map<int,UTM>::const_iterator it;
    
    };
    
    template<> struct
    fwd_type_if_allowed<Knot> { 
    	typedef std::map<int,Knot>::const_iterator it;
    };
    
    template<> struct
    fwd_type_if_allowed<Edge> {
    	typedef std::map<int,Edge>::const_iterator it;
    };
    
    template<> struct
    fwd_type_if_allowed<Face> {
    	typedef std::map<int,Face>::const_iterator it;
    };
    
    template<typename T>
    int function get_id_by_pos(T, int pos) {
    
    	typedef typename fwd_type_if_allowed<T>::it iterator;
    	iterator = destination.begin();
    	for(int i=1;i<pos;i++) iterator++;
    	if(iterator== destination.end()) return 0;
    	else return iterator->first;
    };
    

    Die maps haben als id einen Integer.
    Ich brauche eine Funktion die mir zu einer bestimmten Position die id zurückliefert.

    Irgendwie kriege ich nicht hin, das destination sich jeweils passend zur Klasse wechselt. Könnte jemand ein etwas funktionsfähiges posten?

    Kann man mit der methode at( ) eine bestimmte Position anfahren?

    Nachtrag:

    Max3000 schrieb:

    ...

    Dafür brauche ich doch Boost Bibliotheken?
    Außerdem ist die Frage mit den verschiedenen maps nicht geklärt.



  • Z. B.:

    template<> struct
    fwd_type_if_allowed<UTM> {
        typedef std::map<int,UTM>::const_iterator it;
        static map<int, UTM>* destination;
    };
    
    map<int, UTM>* fwd_type_if_allowed<UTM>::destination = &coords;
    


  • du möchtest die id des pos -ten elements aus der map wiedergeben?

    template<typename T, typename S = typename T::size_type>
    int get_id_by_pos(const T& container, S pos)
    {
      typedef typename container::const_iterator iter_t;
    
      iter_t i = container.begin();
      std::advance(i, pos);
    
      return i->first;
    }
    

    mir scheint aber, dass map nicht der optimale container für dein problem ist!?
    also die position eines elements in einer map anhand der reihenfolge zu speichern, ist nicht gerade das intelligenteste...

    da ich aber vom eigtl thema keinen plan habe, kann ich das nur mal in die runde fragen... ;o)

    bb



  • unskilled schrieb:

    std::advance(i, pos);
    
      return i->first;
    

    Das gibt aua, wenn pos zu groß ist 😉



  • Michael E. schrieb:

    unskilled schrieb:

    std::advance(i, pos);
    
      return i->first;
    

    Das gibt aua, wenn pos zu groß ist 😉

    sicherlich tut es das.
    ist aufgabe des anwendes dafür zu sorgen, keine unsinnigen werte zu übergeben.
    evtl noch nen assert am anfang einfügen:

    template<typename T, typename S = typename T::size_type>
    int get_id_by_pos(const T& container, S pos)
    {
      typedef typename container::const_iterator iter_t;
    
      assert(container.size() > pos && "not a valid position");
    
      iter_t i = container.begin();
      std::advance(i, pos);
    
      return i->first;
    }
    

    bb



  • ...



  • Super!

    Anhand der hier vorgetragenen Codeschnipseln funktioniert es nun!

    #include <iostream>
    
    using namespace std;
    
    template<typename> struct fwd_type_if_allowed { };
    
    template<> struct
    fwd_type_if_allowed<std::map<int, double>> { 
      typedef std::map<int,double>::const_iterator it;
    };
    
    template<> struct
    fwd_type_if_allowed<std::map<int, char>> {
      typedef std::map<int,char>::const_iterator it;
    };
    
    template<typename T, typename S> int get_id_by_pos(const T& container, S pos)
    {
    	typedef typename fwd_type_if_allowed<T>::it iter_t;
    
    	iter_t i = container.begin();
    	std::advance(i, pos-1);
    
    	return i->first;
    } 
    
    int main(int argc, char **argv){
    
    	std::map<int, double> a;
    	std::map<int, char> b; 
    
    	a[11] = 10.1234;
    	a[22] = 20.2345;
    	a[33] = 30.4567;
    
    	b[44] = 'A';
    	b[55] = 'B';
    	b[66] = 'C';
    
    	cout << get_id_by_pos(a,2) << '\n';
    	cout << get_id_by_pos(b,3) << '\n';
    
    	return EXIT_SUCCESS;
    }
    

    Gibt es vielleicht einge Möglichkeit:

    int a = a.get_id_by_pos(1);
    int b = b.get_id_by_pos(2);
    

    Zu templatisieren? Danke schonmal an alle die geantwortet haben.



  • std::advance(i, pos-1);
    nein!? wieso -1?

    oder ist pos == 0 nicht das erste element?

    Gibt es vielleicht einge Möglichkeit:

    int a = a.get_id_by_pos(1);
    int b = b.get_id_by_pos(2);
    

    Zu templatisieren? Danke schonmal an alle die geantwortet haben.

    hm? das da hat aber nix mit "templatisieren" zu tun...
    gehen würde das - ich würd es aber so lassen.

    template<
      typename KEY,
      typename T,
      typename LESS = std::less<KEY>,
      typename ALLOC = std::allocator< std::pair<KEY, T> >
    >
    struct mymap : std::map< KEY, T, LESS, ALLOC >
    {
      KEY get_id_by_pos(size_type pos)
      {
        /*...*/
      }
    };
    

    bb



  • darkfate schrieb:

    Gibt es vielleicht einge Möglichkeit:

    int a = a.get_id_by_pos(1);
    int b = b.get_id_by_pos(2);
    

    Zu templatisieren? Danke schonmal an alle die geantwortet haben.

    Welchen Vorteil siehst du da gegenüber:

    int a = get_id_by_pos(a, 1);
    int b = get_id_by_pos(b, 2);
    

    ? Ich seh da absolut gar keinen.

    Was du da haben möchtest ist eigentlich ein schönes Beispiel für einen boost::multi_index_container. Damit kannst du deine Daten mit verschiedenen Indizes versehen, auch random access.
    http://www.boost.org/doc/libs/1_43_0/libs/multi_index/doc/tutorial/index.html



  • brotbernd schrieb:

    .. Welchen Vorteil siehst du da gegenüber: ..

    Du hast recht, es ist ok so wie es ist. Mir ging es lediglich um die Machbarkeit.

    unskilled schrieb:

    std::advance(i, pos-1);
    nein!? wieso -1?

    oder ist pos == 0 nicht das erste element?

    it.begin() setzt ihn ja auf die erste Position.
    Wenn man jetzt get_id_by_pos(1) aufruft, dann schiebt er
    den Iterator nach begin() noch um eine Position weiter.

    Für mich sind alle Fragen geklärt.
    Danke an alle Helfenden.


Anmelden zum Antworten