[ERLEDIGT] template einschränken



  • Hallo Leute,

    ich habe vier Funktionen die nahezu identisch sind,
    jedoch auf vier verschiedene Klassen angewendet werden.
    Ich möchte sie zu einem template Zusammenfassen.
    Kann ich es so einschränken, dass nur diese vier Klassen
    dieses template verwenden dürfen?

    Wenn ja wie?

    // Die Typedefs
    typedef std::map<PANO_UINT,UTM>::const_iterator UTM_CONST_ITERATOR;
    typedef std::map<PANO_UINT,Knot>::const_iterator KNOT_CONST_ITERATOR;
    typedef std::map<PANO_UINT,Edge>::const_iterator EDGE_CONST_ITERATOR;
    typedef std::map<PANO_UINT,Face>::const_iterator FACE_CONST_ITERATOR;
    
    //Die Funktion ... als Beispiel für die Klasse UTM
    PANO_UINT GEOTopology::get_coord_id_by_pos(PANO_UINT position_in_map) const{
    
    	UTM_CONST_ITERATOR utmconstit = coords.begin();
    	for(PANO_UINT i=1;i<position_in_map;i++) utmconstit++;
    	if(utmconstit == coords.end()) return 0;
    	else return utmconstit->first;
    }
    


  • Beispielsweise

    template<typename> struct fwd_type_if_allowed { };
    template<> struct fwd_type_if_allowed<erlaubte_klasse_1> { typedef erlaubte_klasse_1 type; };
    template<> struct fwd_type_if_allowed<erlaubte_klasse_2> { typedef erlaubte_klasse_2 type; };
    
    // ...
    
    template<typename T>
    class foo {
      typedef typename fwd_type_if_allowed<T>::type value_type;
    };
    

    Wenn jemand das mit einem nicht whitegelisteten Typ versucht, kann fwd_type_if_allowed<T>::type nicht aufgelöst werden und das ganze geht daneben.



  • Warum willst du es einschränken? Wenn jemand das benötigte Interface zur Verfügung stellt, dann ist das doch auch Ok, oder?

    Es gibt Wege, wie du oben siehst, aber ich halte das oft für gar nicht nötig, dass du das einschränkst.

    btw:
    Die Funktion gibt es bereits mehr oder weniger bereits:
    http://www.cplusplus.com/reference/std/iterator/advance/



  • drakon schrieb:

    Warum willst du es einschränken? Wenn jemand das benötigte Interface zur Verfügung stellt, dann ist das doch auch Ok, oder?

    Es gibt Wege, wie du oben siehst, aber ich halte das oft für gar nicht nötig, dass du das einschränkst.

    btw:
    Die Funktion gibt es bereits mehr oder weniger bereits:
    http://www.cplusplus.com/reference/std/iterator/advance/

    Weil ich eine Templatefunktion für vier Topologieklassen erstellen möchte und sie woanders keinen Sinn machen. Wenn es doch etwas gibt, kann ich sie ja immer noch freischalten.

    seldon schrieb:

    Beispielsweise

    template<typename> struct fwd_type_if_allowed { };
    template<> struct fwd_type_if_allowed<erlaubte_klasse_1> { typedef erlaubte_klasse_1 type; };
    template<> struct fwd_type_if_allowed<erlaubte_klasse_2> { typedef erlaubte_klasse_2 type; };
    
    // ...
    
    template<typename T>
    class foo {
      typedef typename fwd_type_if_allowed<T>::type value_type;
    };
    

    Wenn jemand das mit einem nicht whitegelisteten Typ versucht, kann fwd_type_if_allowed<T>::type nicht aufgelöst werden und das ganze geht daneben.

    Also damit habe ich ein wenig Probleme.

    Wie sieht es dann im Endeffekt aus? So etwa?

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

    Wie kriege ich es hin dass ich mit dem Iterator das Ziel, die std::map in der ich suche auch geändert wird?



  • darkfate schrieb:

    Weil ich eine Templatefunktion für vier Topologieklassen erstellen möchte und sie woanders keinen Sinn machen. Wenn es doch etwas gibt, kann ich sie ja immer noch freischalten.

    Normalerweise arbeitet man andersrum. Du verhinderst ja auch nicht die Vererbung von von deiner Klasse Base für alle Typen außer Derived1, Derived2, ... 😉 Vorausgesetzt der Funktionsname ist gut, wird keiner auf die Idee kommen, die Funktion zu benutzen, wenn sie keinen Sinn macht. Daher brauchst du auch keine technische Einschränkung.



  • Michael E. schrieb:

    darkfate schrieb:

    Weil ich eine Templatefunktion für vier Topologieklassen erstellen möchte und sie woanders keinen Sinn machen. Wenn es doch etwas gibt, kann ich sie ja immer noch freischalten.

    Normalerweise arbeitet man andersrum. Du verhinderst ja auch nicht die Vererbung von von deiner Klasse Base für alle Typen außer Derived1, Derived2, ... 😉 Vorausgesetzt der Funktionsname ist gut, wird keiner auf die Idee kommen, die Funktion zu benutzen, wenn sie keinen Sinn macht. Daher brauchst du auch keine technische Einschränkung.

    Ja ok, dann nenne mir bitte ein Beispiel außer knoten(koordinate),kante,masche die ein topologisches Objekt darstellen soll?

    Außerdem würde es mir sehr helfen, wenn jemand mal da oben den code anschauen könnte und eventuell einen tipp warum es noch nicht funktioniert?



  • struct baum : std::string
    {};
    

    oder

    struct mensch : std::complex<int>
    {};
    

    ergibt auch beides keinen sinn - trotzdem geht es.

    es gibt so viele dinge, die unlogisch sind und trotzdem gehen - wenn man sich jedes mal nen kopf machen würde um all das zu verbieten, würde man nie fertig...

    bb



  • unskilled schrieb:

    ...

    Wie kriege ich es hin dass außer T auch noch die richtige Zielmap angesprochen wird?



  • btw:

    template<> struct
    fwd_type_if_allowed<UTM> {
        typedef std::map<PANO_UINT,UTM>::const_iterator it;
        typedef dest this->coords;
    }
    

    das ist mit sicherheit falsch - was möchtest du mit dem zweiten typedef bewirken?

    Wie kriege ich es hin dass außer T auch noch die richtige Zielmap angesprochen wird?

    hm? Sry, hab den Thread nur überflogen... ^^

    bb



  • unskilled schrieb:

    ..

    Ich möchte mit einer Templatefunktion vier std::maps (Namen: coords,knots,edges,faces) durchsuchen können.

    Im Grunde geht es einfach darum an eine bestimmte Position (Integerwert von Anfang an gezählt) zu fahren und von dort aus die id zurückzugeben.

    Vielleicht wäre es besser gefragt ob es nicht schon solche STL Methode gibt?

    Dennoch wäre es interessant zu wissen wie man so eine Einschränkung durchführen kann. Sei es nun sinnvoll oder nicht.



  • darkfate schrieb:

    Ja ok, dann nenne mir bitte ein Beispiel außer knoten(koordinate),kante,masche die ein topologisches Objekt darstellen soll?

    Wir verstehen offensichtlich unter topologischen Objekten etwas Unterschiedliches, weshalb ich dir die Frage nicht beantworten kann. Mal schnell nachgeschaut, http://de.wikipedia.org/wiki/Geoobjekt#Topologie spricht von deinen drei Typen. Wenns keine andere Verwendungsmöglichkeit für die Funktion gibt außer für diese drei Typen, wird sie auch keiner mit einem anderen Typen verwenden und das Problem löst sich von selbst 🙂

    Edit: Du sprichst von drei topologischen Grundtypen, hast aber vier Typen in deinem Quellcode, für die du die Funktion zugänglich machen willst. Eventuell hast du einen fünften vergessen oder stell dir vor, du hättest den vierten vergessen...



  • Michael E. schrieb:

    ...

    Wie bereits mehrfach angesprochen, möchte ich trotzdem wissen wie man es in Code umsetzen könnte.

    Nachtrag:
    Ich würde doch gern bitten den Post durchzulesen. Es geht nicht um Einschränken oder nicht. Sinnvoll oder nicht. Darüber brauchen wir nicht zu diskutieren.

    Es geht darum, dass mit diesen vier vorliegenden Klassen auch vier verschiedene std::maps angesprochen werden.

    Für die Klasse UTM soll im Template die vorhandene std::map variable coords abgefragt werden.

    Für die Klasse Knot -> knots
    Für die Klasse Edge -> edges
    Für die Klasse Face -> faces



  • wurde doch schon gesagt - entweder durch eine whitelist:

    template<typename T>
    struct type_if_allowed;
    
    struct type_if_allowed<foo>
    {
      typedef int bar;
    };
    

    oder andersrum - also ne blacklist:

    template<typename T>
    struct type_if_allowed
    {
      typedef T bar;
    };
    
    struct type_if_allowed <foo>
    {};
    

    Verwendung auch wie schon gesagt:

    template<typename T>
    void test(const T& x)
    {
      typedef typename type_if_allowed<foo>::bar foo;
    
      /*
        ...
      */
    }
    

    bb



  • Hey.

    Ich hab mir zwar nicht alle Vorposts durchgelesen aber ich glaube ich weiß was du brauchst.

    Also erstmal definierst du ein template, was von boost::mpl::false_ erbt und das spezialisierst du für deine 4 Klassen, und die erben dann von boost::mpl::true_. Ich habe hier mal ein kleines Beispiel wo ich das gebraucht habe. Da wollte ich eine Funktion, die nur für float, double, complex<float> und complex<double> verfügbar ist:

    template <typename T>
    struct is_blas_type : boost::mpl::false_
    {};
    
    // FLOAT is a type supported by BLAS
    template <>
    struct is_blas_type<float> : boost::mpl::true_
    {};
    
    // DOUBLE is a type supported by BLAS
    template <>
    struct is_blas_type<double> : boost::mpl::true_
    {};
    
    // COMPLEX_FLOAT is a type supported by BLAS
    template <>
    struct is_blas_type<std::complex<float> > : boost::mpl::true_
    {};
    
    // COMPLEX_DOUBLE is a type supported by BLAS
    template <>
    struct is_blas_type<std::complex<double> > : boost::mpl::true_
    {};
    
    template <typename T, typename U= void>
    struct enable_if_blas_type
      : boost::enable_if<is_blas_type<T>, U>
    {};
    
    }
    

    Dann definierst du den Rückgabewert deiner Funktion mit deinem enable_if, zum Beispiel:

    template <typename T>
    typename boost::enable_if_c<is_blas_type<T>::value, T>::type
    inline dot(vector<T> &v1, vector<T> &v2)
    {...}
    

    Das enable_if_c nimmt als erstes Templateargument dein struct, was entweder von true oder false erbt und wenn es false ist, gibts diese Funktion für deinen typename T im Prinzip gar nicht. Das zweite Argument ist dann der Rückgabetyp der Funktion und ist standardmäßig void.

    Das _c bei enable_if_c und das ::value kannst du auch weglassen, dann sucht der automatisch nach nem Typen value.

    Ich denke das ist doch das was du brauchst oder?

    Grüße

    Max



  • Hab noch vergessen dass das alles in

    #include <boost/utility/enable_if.hpp>
    #include <boost/mpl/bool.hpp>
    

    zu finden ist.



  • unskilled schrieb:

    ...

    Das habe ich hingekriegt. Es geht um was anderes. Die Problemstellung befindet sich über deinem (zitierten) Post.



  • Definier halt

    typedef std::map<PANO_UINT, typename fwd_type_if_allowed<T>::type> coords_type;
    
    coords_type coords;
    
    // Später
    
    typename coords_type::const_iterator iter = coords.begin();
    

    Wie 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.



  • Michael E. schrieb:

    Wenns keine andere Verwendungsmöglichkeit für die Funktion gibt außer für diese drei Typen, wird sie auch keiner mit einem anderen Typen verwenden und das Problem löst sich von selbst 🙂

    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.



  • 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.


Log in to reply