Problem mit Templatemtaprogrammierung (Fibonacci-Zahlen)



  • Hallo zusammen,

    ich versuche gerade mit TMP zur Compilezeit Fibonacci-Zahlen berechnen zu lassen, aber komischerweise kommt immer 0 als Ergebnis raus.
    Bitte helft mir 🙂

    Hier ist der Code:

    template<int n>
    struct fib
    {
      static const int value;
    };
    
    template<>
    struct fib<0>
    {
      static const int value = 0;
    }
    
    template<>
    struct fib<1>
    {
      static const int value = 1;
    }
    
    template<int n>
    const int fib<n>::value = fib<n-1>::value + fib<n-2>::value;
    
    int main()
    {
       std::cout << fib<5>::value << endl;
       std::cin.peek();
    }
    

    Ausgabe: 0

    Vielen Dank schonmal im Voraus für eure Hilfe!



  • Ich würde es so machen: http://ideone.com/rmPXF



  • Fast:

    template<int n>
    struct fib
    {
      static const int value = fib<n-1>::value + fib<n-2>::value;
    };
    
    template<>
    struct fib<0>
    {
      static const int value = 0;
    };
    
    template<>
    struct fib<1>
    {
      static const int value = 1;
    };
    


  • 314159265358979 schrieb:

    Ich würde es so machen: http://ideone.com/rmPXF

    Sieht irgendwie falsch aus.


  • Mod

    An sich sollte auch dein Programm funktionieren, wenn man alle Syntaxfehler korrigiert, so dass es überhaupt compiliert:

    #include<iostream>
    
    template<int n>
    struct fib
    {
      static const int value;
    };
    
    template<>
    struct fib<0>
    {
      static const int value = 0;
    };
    
    template<>
    struct fib<1>
    {
      static const int value = 1;
    };
    
    template<int n>
    const int fib<n>::value = fib<n-1>::value + fib<n-2>::value;
    
    int main()
    {
      std::cout << fib<6>::value << std::endl;
      std::cin.peek();
    }
    

    Daher vermute ich mal, dass du uns nicht das eigentliche Programm gezeigt hast und beim Abschreiben deinen Fehler schon versehentlich korrigiert hast.



  • Tachyon schrieb:

    314159265358979 schrieb:

    Ich würde es so machen: http://ideone.com/rmPXF

    Sieht irgendwie falsch aus.

    Nö, funktioniert.

    Edit: Du hast Recht, die Fibonacci Zahlen beginnen bei 0, habe mit 1 angefangen. Hier korrigiert: http://ideone.com/Tovce



  • 314159265358979 schrieb:

    Tachyon schrieb:

    314159265358979 schrieb:

    Ich würde es so machen: http://ideone.com/rmPXF

    Sieht irgendwie falsch aus.

    Nö, funktioniert.

    Die Ergebnisse sind aber falsch. Die Spezialisierung fib<0> ist nicht in Ordnung.


  • Mod

    Verschieb mal den Initialisierer in die Klasse:

    template<int n>
    struct fib
    {
      static const int value = fib<n-1>::value + fib<n-2>::value;
    };
    ...
    template<int n>
    const int fib<n>::value;
    


  • camper schrieb:

    Verschieb mal den Initialisierer in die Klasse:

    template<int n>
    struct fib
    {
      static const int value = fib<n-1>::value + fib<n-2>::value;
    };
    ...
    template<int n>
    const int fib<n>::value;
    

    Wozu braucht es diesen Teil:

    template<int n>
    const int fib<n>::value;
    

    überhaupt noch?


  • Mod

    Tachyon schrieb:

    Wozu braucht es diesen Teil:

    template<int n>
    const int fib<n>::value;
    

    überhaupt noch?

    Wegen der ODR (3.2/3, Definition für used in 3.2/2).

    Das gibt uns auch den Hinweis darauf, warum der ursprüngliche Code fehlschlagen kann, da der Kontext

    std::cout << fib<5>::value
    

    keinen konstanten Ausdruck auf der rechten Seite benötigt, wird die rechte Seite nur potentiell ausgewertet i.o.S.
    Das wiederum bedeutet, dass der Compiler möglicherweise keine Definition benötigt und folglich keine Instantiierung vornimmt. Ohne Instantiierung der Konstanten wird auch nicht der Initialisierer instantiiert.
    Natürlich ist das trotzdem komisch, denn ohne den Initialisierer zu instantiieren, kann der Compiler nicht wissen, ob überhaupt ein konstanter Ausdruck vorliegt.
    Jedenfalls bieten sich mehrere Lösungen an: entweder wird der Initialisierer verschoben und hängt damit nicht mehr an der Defintion der Konstanten selbst. Oder es wird explizit dafür gesorgt dass eine Instantiierung erfolgt (2). Oder wir wechseln in einen Kontext, der einen konstanten Ausdruck benötigt (3). Oder wir machen aus value einen nicht-konstanten Ausdruck (4).

    template<int n>
    const int fib<n>::value = fib<n-1>::value + fib<n-2>::value + 0.0; // (4)
    
    template fib<6>::value; // (2) explizite Instantiierung
    
    int main()
    {
        &fib<6>::value; // (2) implizite Instantiierung erforderlich
        std::cout << sizeof(char[fib<6>::value]); // (3) konstanter Ausdruck erforderlich
    

Anmelden zum Antworten