Problem mit Rekursion bei Templates ohne Spezialisierung



  • Ich über gerade etwas mit Templates und mir ist aufgefallen, dass ich einen Stopp der Rekursion nur durch die Spezialisierung für 0 erreichen kann, warum nicht so:

    template <int Number>
    struct NonSense {
        const static bool value = Number == 0 ? true : NonSense<Number - 1>::value;
    };
    
    int main() {
        NonSense<2>::value;
    }
    
    error: template instantiation depth exceeds maximum of 500 (use -ftemplate-depth-NN to increase the maximum) instantiating `struct NonSense<-0x0000001f2>'
    

    Sollte er nicht, sobald Number 0 ist, aufhören sich nochmal aufzurufen?

    mfg.



  • Erstelle eine explizite Spezialisierung des Templates für Number=0.

    template <int Number>
    struct NonSense {
        const static bool value =  NonSense<Number - 1>::value;
    };
    
    template <> struct NonSense <0>{
        const static bool value =  true;
    };
    
    int main() {
        NonSense<2>::value;
    }
    

    Der Code funktioniert.



  • joomoo schrieb:

    ...und mir ist aufgefallen, dass ich einen Stopp der Rekursion nur durch die Spezialisierung für 0 erreichen kann, warum nicht so:



  • Das liegt daran, daß beim ?:-Operator zur Compilerzeit immer beide alternativen ausgewertet werden. Dadurch bricht die Rekursion nie ab.



  • Jester schrieb:

    Das liegt daran, daß beim ?:-Operator zur Compilerzeit immer beide alternativen ausgewertet werden. Dadurch bricht die Rekursion nie ab.

    Achso. Danke, das hab ich gesucht.

    mfg.


  • Mod

    Jester schrieb:

    Das liegt daran, daß beim ?:-Operator zur Compilerzeit immer beide alternativen ausgewertet werden. Dadurch bricht die Rekursion nie ab.

    "auswertung" ist hier ein ungünstiger begriff - für gewöhnlich meint man damit ja das ermitteln des "wertes" eines ausdrucks. unter diesem gesichtspunkt wäre es schwer verständlich, warum sich ?: bei templates anders verhalten sollte als beim programmablauf. das problem hier ist dagegen die ermittelung des typs des ergebnisses des ?: operators. dieser hängt von den typen des zweiten und dritten operanden ab - völlig unabhängig davon, was der erste operand ist. folglich müssen irgendwelche templates, die teil dieser operanden sind, zumindest instantiiert werden, um vollständige typen zu erhalten.



  • camper schrieb:

    das problem hier ist dagegen die ermittelung des typs des ergebnisses des ?: operators. dieser hängt von den typen des zweiten und dritten operanden ab - völlig unabhängig davon, was der erste operand ist. folglich müssen irgendwelche templates, die teil dieser operanden sind, zumindest instantiiert werden, um vollständige typen zu erhalten.

    Ich sehe nicht, inwiefern das die Sache jetzt besser erklärt. Warum darf der Compiler nicht sehen, daß wenn vorne true steht der Ergebnistyp nur vom ersten Operanden abhängt?

    edit: Oder soll damit nur int x = true ? 3 : std::vector(); verhindert werden?


  • Mod

    oder auch

    #include <iostream>
    
    using namespace std;
    
    typedef long long i64;
    template<int x> struct Foo { static const int value = -x; };
    template<> struct Foo<0> { static const unsigned value = 10; };
    
    const i64 v1 = true ? Foo<10>::value : Foo<9>::value;
    const i64 v2 = true ? Foo<10>::value : Foo<0>::value;
    
    int main()
    {
    	cout << v1 << endl;
    	cout << v2 << endl;
    }
    

    ergibt
    -10
    4294967286

    obwohl der rechte operand nie ausgewertet wird, beeinflußt sein typ doch das ergebnis (ignorieren wir hier mal, daß das formal undefiertes verhalten ist - sicherlich kann man auch ein korrektes beispiel produzieren).


Anmelden zum Antworten