Sind rekursive Templatefunktionen wohlgeformt?


  • Mod

    otze schrieb:

    Oder sagt er sogar, dass dieses Programm nicht wohlgeformt ist?

    nein, der Standard sagt, dass das Ergebnis unbegrenzter impliziter Instantiierung undefiniert ist... also im Prinzip ja (14.7.1/15) 😉

    C++11 schrieb:

    14.7.1 Implicit instantiation [temp.inst]
    [...]
    3 Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.

    ===>

    C++11 schrieb:

    3.2 One definition rule [basic.def.odr]
    [...]
    3 Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is odr-used.

    ===>

    C++11 schrieb:

    3.2 One definition rule [basic.def.odr]
    [...]
    2 An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. this is odr-used if it appears as a potentially-evaluated expression (including as the result of the implicit transformation in the body of a non-static member function (9.3.1)). A virtual member function is odr-used if it is not pure. A non-overloaded function whose name appears as a potentially-evaluated expression or a member of a set of candidate functions, if selected by overload resolution when referred to from a potentially-evaluated expression, is odr-used, unless it is a pure virtual function and its name is not explicitly qualified. [ Note: This covers calls to named functions (5.2.2), operator overloading (Clause 13), user-defined conversions (12.3.2), allocation function for placement new (5.3.4), as well as non-default initialization (8.5). A copy constructor or move constructor is odr-used even if the call is actually elided by the implementation. —end note ][...]

    Der Ausdruck

    myFunc(makeBar(t));
    

    wird potentiell ausgewerted in obigem Sinne (unabhängig davon, dass man ggf. beweisen könnte, dass er für einen bestimmten Typ nie tatsächlich ausgewertet wird), folglich muss die entsprechende Funktion existieren, folglich wird diese Spezialisierung implizit instantiiert werden.

    Das ganze funktioniert also nur, wenn du es mit konstanten Ausdrücken zu tun hast, denn dann werden Teile, die nicht ausgewertet werden auch nicht odr-genutzt. Beispiel

    template <int N>
    struct foo   // Hab den Namen dieser Funktion vergessen 
    {
        static const int value = N == 1 ? 1 : N % 2 == 0 ? foo<N/2>::value : foo<3*N+1>::value;
    };
    


  • Du hast zu viel Zeit, stimmts camper?



  • Kann m.E. nur 2. sein, weil Optimierungen zum Laufzeitverhalten gehören und nicht die statische Typprüfung beeinflussen können.


  • Mod

    314159265358979 schrieb:

    Du hast zu viel Zeit, stimmts camper?

    Scheint so; schliesslich verschwende ich sie, um deine Frage zu beantworten.



  • Wow. Danke für diese tolle Antwort, Camper. Exakt das, was ich gesucht habe. Naja. Dann überlege ich mir wohl besser was neues, um meine Logik zu vereinfachen. In dem Fall könnte ich auch einfach code duplizierung betreiben und beide Fälle explizit behandeln.

    //edit foo ist in deinem Flal wohl die Collatz-Folge? 😉



  • 314159265358979 schrieb:

    Du hast zu viel Zeit, stimmts camper?

    Naja, er ist schon recht selektiv, was die Beantwortung von Fragen angeht. Und wenn's dann soweit ist, gibt's meist 'ne gute, ausführliche…



  • Ich hab das jetzt nicht mal böse gemeint, genau das wundert mich eben. Hätte nicht die Motivation wegen jedem Mist den Standard zu durchsuchen.


  • Mod

    otze schrieb:

    //edit foo ist in deinem Flal wohl die Collatz-Folge? 😉

    ja, allerdings ist mir gerade aufgefallen, dass das Beispiel so nicht funktioniert. Auch in diesem Fall kommt es (ohne zusätzliche Spezialisierungen) zu unbegrenzter rekursiver Instantiierung. Damit die Instantiierung abbrechen kann, müsste nachgewiesen werden, dass foo<...>::value in einem konstanten Ausdurck verwendet werden kann. Dass ist aber nur der Fall, wenn es sich um ein konstantes Objekt handelt (dieser Test erfordert keine Instantiierung), der mit einem konstanten Ausdruck initialisiert wurde (hierfür ist eine Instantiierung erforderlich).



  • 314159265358979 schrieb:

    Hätte nicht die Motivation wegen jedem Mist den Standard zu durchsuchen.

    Ich wage zu behaupten, dass std::camper da nicht lange suchen muss sondern ziemlich genau weiß, wo die Dinge stehen 😉



  • Das mag schon sein, aber das auch kopieren und so.


Anmelden zum Antworten