type deduction fuer nontype template parameters



  • Hallo liebe Community,

    Bevor ich einen Proposal schreibe, moechte ich mich erstmal mit meiner Idee an euch wenden, vielleicht habe ich ja irgendwas wichtiges uebersehen, oder mir faellt noch etwas ein, was ich noch unbedingt brauche. 🙂

    Ich schlage vor, type deduction fuer template-Value-Parameter hinzuzufuegen. Das soll zum einen der Vereinfachung dienen, andererseits wird es damit moeglich, Parameter-Packs von Variadic Templates in Value-Parametern zu verwenden. (Sorry, mir ist da keine bessere Formulierung eingefallen, bei Unklarheiten bitte nachfragen 😉 )

    Syntaxmaessig sieht das dann so aus:

    template <auto T, T Value> // (!)
    struct foo
    {};
    
    template <auto C, auto R, auto... P, R (C::* Ptr) (P...) const> // (!)
    struct bar
    {};
    
    struct baz
    {
        void f() const;
    };
    
    extern int i;
    
    foo<42> f1; // T deduced to `int'
    foo<&baz::f> f2; // T deduced to  `void (bar::*) () const'
    foo<&i> f2; // T deduced to  `int*'
    bar<&baz::f> b; // C deduced to `baz', R deduced to `void', P... deduced to {}
    

    Deduzierte Typparameter koennen nicht explizit angegeben werden. Sie koennen an einer beliebigen Stelle der Parameterliste stehen, muessen allerdings vor ihrer Verwendung definiert sein. Type-Deduction muss, wie bei Funktionsparametern, fuer alle Argumente, in denen sie verwendet werden, erfolgreich sein, damit das Template instanziert werden kann.

    Was haltet ihr davon?
    Vorschlaege? Wuensche? Verbesserungen? :p

    Gruesse,
    Der Kellerautomat


  • Mod

    Erscheint mir etwas zu kompliziert.
    Wie wäre es mit

    template <auto Value>
    struct foo
    {
      // decltype(Value) wenn der Typ benötigt wird
    };
    
    template <typename T, T* Value> // bei Spezialisierungen taucht der Typ automatisch auf
    struct foo<value> 
    {
    };
    
    template <auto X>
    struct bar;
    
    template <auto C, auto R, auto... P, R (C::* Ptr) (P...) const>
    struct bar<Ptr>
    {
    };
    

    soweit ich das überblicke, benötigt man hierfür keine neuen Deduktionsregeln.
    Etwas komplizierter wird es evtl., wenn man auch auto-Parameterpacks haben will.



  • Diese Syntax hatte ich davor. Dass man natuerlich einfach spezialisieren kann, habe ich dabei nicht bedacht.

    Bei struct bar meintest du wohl folgendes, oder?

    template <typename C, typename R, typename... P, R (C::* Ptr) (P...) const>
    struct bar<Ptr>
    {
    };
    

    Deduktionsregeln braucht man hier selbstverstaendlich keine neuen, hier koennen die gleiche wie bei Funktionsparametern zum einsatz kommen. Durch Einschraenkungen, was ein Template-Value-Parameter ueberhaupt sein kann, wird es evtl. sogar etwas einfacher.

    Was meinst du mit auto-Parameter Packs? Inwiefern wuerden sich hier die Regeln unterscheiden?


  • Mod

    Kellerautomat schrieb:

    DBei struct bar meintest du wohl folgendes, oder?

    template <typename C, typename R, typename... P, R (C::* Ptr) (P...) const>
    struct bar<Ptr>
    {
    };
    

    äh, ja.

    Deduktionsregeln braucht man hier selbstverstaendlich keine neuen, hier koennen die gleiche wie bei Funktionsparametern zum einsatz kommen. Durch Einschraenkungen, was ein Template-Value-Parameter ueberhaupt sein kann, wird es evtl. sogar etwas einfacher.

    Kellerautomat schrieb:

    Was meinst du mit auto-Parameter Packs? Inwiefern wuerden sich hier die Regeln unterscheiden?

    non-type Parameterpacks bestehen gegenwärtig aus Werten eines einzigen Typs. Es wäre zu überlegen, ob diese Beschränkung beibehalten werden soll

    template <auto... x>
    struct foo;
    
    template <typename... T, T... x>
    struct foo<x...> {};
    // oder
    template <typename T, T... x>
    struct foo<x...> {};
    // ? evtl. könnte auch beides erlaubt werden
    

    Eine weitere Verallgemeinerung könnte ggf. auch in Verbindung mit anderen Parameterarten eingeführt werden, indem eine weitere Kategorie eingeführt wird, ich nenne sie mal polymorph:
    definiere: ein polymorpher Parameter P wird deklariert durch

    void P
    

    jedes allgemein für Template-, Typ- oder nicht-Typ-parameter mögliche Argument ist ein zulässiges Argument für einen polymorphen Parameter. Innerhalb einer Templatedefinition kann ein polymorpher Parameter nur als Templateargument verwendet werden (einfacheste Lösung, die auch mit Aliastemplates kompatibel ist) - an irgendeinem Punkt muss also spezialisiert werden. Damit könnte dann z.B. ein std::set so modifiziert werden, dass es auch direkt mit Vergleichsfunktionen als Templateargument zurecht kommt.
    Eine gute Idee für eine allgemeinere Deklaration (und eine Methode, diese in Spezialisierungen vernünftig auseinander zu nehmen) für Template-template-parameter habe ich allerdings nicht.



  • camper schrieb:

    non-type Parameterpacks bestehen gegenwärtig aus Werten eines einzigen Typs. Es wäre zu überlegen, ob diese Beschränkung beibehalten werden soll

    template <auto... x>
    struct foo;
    
    template <typename... T, T... x>
    struct foo<x...> {};
    // oder
    template <typename T, T... x>
    struct foo<x...> {};
    // ? evtl. könnte auch beides erlaubt werden
    

    Ich wuerde sagen, auto... steht fuer ein Parameter-Pack von Werten beliebigen Typs. Wer nur einen Typ haben moechte, der kann ja spezialisieren:

    template <auto...>
    struct foo
    {
        // allg., verschiedene Typen
    };
    
    template <typename T, T... V>
    struct foo<V...>
    {
        // nur ein Typ erlaubt
    };
    

    camper schrieb:

    Eine weitere Verallgemeinerung könnte ggf. auch in Verbindung mit anderen Parameterarten eingeführt werden, indem eine weitere Kategorie eingeführt wird, ich nenne sie mal polymorph:
    definiere: ein polymorpher Parameter P wird deklariert durch

    void P
    

    jedes allgemein für Template-, Typ- oder nicht-Typ-parameter mögliche Argument ist ein zulässiges Argument für einen polymorphen Parameter. Innerhalb einer Templatedefinition kann ein polymorpher Parameter nur als Templateargument verwendet werden (einfacheste Lösung, die auch mit Aliastemplates kompatibel ist) - an irgendeinem Punkt muss also spezialisiert werden. Damit könnte dann z.B. ein std::set so modifiziert werden, dass es auch direkt mit Vergleichsfunktionen als Templateargument zurecht kommt.
    Eine gute Idee für eine allgemeinere Deklaration (und eine Methode, diese in Spezialisierungen vernünftig auseinander zu nehmen) für Template-template-parameter habe ich allerdings nicht.

    Wenn ich das richtig verstanden habe, kommt das "weakly specified parameters" aus diesem Proposal recht nahe: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3416.html


Anmelden zum Antworten