[ERLEDIGT] template einschränken



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



  • 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



  • ...


Anmelden zum Antworten