Probleme mit teilweiser Template Spezialisierung



  • Ich habe folgenden Pseudo-Code

    template < std::size_t numEntries, std::size_t sizeEntry, typename T >
    class MemoryPool
    {
        MemoryPool()
        {
            ...
        }
    
        ...
    };
    

    Und wollte jetzt eine teilweise "Spezialisierung" vornehmen:

    template < std::size_t numEntries, typename T >
    class MemoryPool<numEntries, sizeof(T), T>;
    

    Das funktioniert nicht. Warum und was muss ich machen damit es funktioniert?



  • "Pseudo-Code"?
    "funktioniert nicht" bedeutet was?


  • Mod

    C++ verbietet dieses Szenario (warum auch immer, wenn jemand den Grund weiß, bitte melden):

    A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

    Der Trick ist nun, dass das nur für non-types gilt. Also machen wir das Argument zu einem Type! Da das aber wahrscheinlich nervig für den Benutzer wäre, wrappe ich das noch einmal, damit der Benutzer eine Zahl angeben kann, anstatt einen Hilftypen:

    #include <cstddef>
    #include <iostream>
    
    template <std::size_t s> struct SizeTType {static const std::size_t size = s;};
    
    template < std::size_t numEntries, typename sizeEntry, typename T >
    struct MemoryPoolBackend
    {
      static const std::size_t size = sizeEntry::size;
      MemoryPoolBackend() {std::cout << "Non specialized: " << size << '\n';}
    };
    
    template < std::size_t numEntries, typename T >
    struct MemoryPoolBackend<numEntries, SizeTType<sizeof(T)>, T>
    {
      static const std::size_t size = sizeof(T);
      MemoryPoolBackend() {std::cout << "Specialized: " << size << '\n';}
    };
    
    template < std::size_t numEntries, std::size_t sizeEntry, typename T >
    class MemoryPool: public MemoryPoolBackend<numEntries, SizeTType<sizeEntry>, T> {};
    
    int main()
    {
      MemoryPool<1,2,double> non_specialized;
      MemoryPool<123, 1, char> specialized;
      MemoryPool<567, sizeof(std::istream), std::istream> also_specialized;
    }
    


  • Do you get the following error`?

    main.cpp:16:7: error: template argument 'sizeof (T)' involves template parameter(s)

    I think, the sizeof Operator is inappropriate. It just doesn't work with template arguments, it's more or less a preprocessor macro.
    You need to search for a workaraound.



  • @SeppJ

    Du hast mich genau verkehrtherum verstanden 😉

    Die Idee war das ich Situationen habe wo ich:

    MemoryPool<1000, MAX_ITEM_SIZE_FOO, Foo> memoryPool;
    

    nutze und ich habe aber auch Fälle wo:

    MemoryPool<1000, Foo> memoryPool;
    

    schöner wäre und ich im Moment noch:

    MemoryPool<1000, sizeof(Foo), Foo> memoryPool;
    

    schreiben muss.

    Aber ich werde deins Trotzdem mal so herum ausprobieren wie oben beschrieben.

    Edit::

    Ok, irgendwie bekomme ich es nicht hin 😞


  • Mod

    FlashBurn schrieb:

    @SeppJ

    Du hast mich genau verkehrtherum verstanden 😉

    Die Idee war das ich Situationen habe wo ich:

    MemoryPool<1000, MAX_ITEM_SIZE_FOO, Foo> memoryPool;
    

    nutze und ich habe aber auch Fälle wo:

    MemoryPool<1000, Foo> memoryPool;
    

    schöner wäre und ich im Moment noch:

    MemoryPool<1000, sizeof(Foo), Foo> memoryPool;
    

    schreiben muss.

    Das ist aber keine Spezialisierung, sondern ein Defaultargument. Quasi das genaue Gegenteil! Kein Wunder, dass du schreibst, dass ich dich genau verkehrt herum verstanden hätte, wenn du doch nach Spezialisierungen gefragt hast.

    In Defaultargumenten ist das kein Problem, keine Verrenkungen notwendig:

    #include <cstdlib>
    #include <iostream>
    
    template < typename T, std::size_t numEntries, std::size_t sizeEntry = sizeof(T\
    )>
    struct MemoryPool
    {
      MemoryPool()
      {
        std::cout << "Size is " << sizeEntry << '\n';
      }
    };
    
    int main()
    {
      MemoryPool<double, 1, 2> foo;
      MemoryPool<double, 1> bar;
    }
    

    Potentielle Defaultargumente müssen natürlich nachfolgend zu allen Argumenten sein, die zwingend gegeben sein müssen. Denn sonst könnte schließlich nicht unterschieden werden, welcher Parameter nun welches Argument sein soll.



  • @SeppJ

    Danke! Das mit den Defaultargumenten kannte ich bei Templates noch nicht, aber auf die Idee bin ich auch gar nicht erst gekommen.
    Ich bin irgendwie auf dem Weg gewesen, dass das eine Spezialisierung ist 😉


  • Mod

    FlashBurn schrieb:

    @SeppJ

    Danke! Das mit den Defaultargumenten kannte ich bei Templates noch nicht, aber auf die Idee bin ich auch gar nicht erst gekommen.
    Ich bin irgendwie auf dem Weg gewesen, dass das eine Spezialisierung ist 😉

    Daher merke dir: Frage stets nach dem, was du erreichen möchtest! Nicht nach dem, was du denkst, wie die Lösung aussehen könnte. Jetzt haben wir beide viel Zeit und Arbeit verschwendet auf etwas, das gar nicht relevant war. Es ist ok (und oft auch gut), zu deinem Ziel auch deinen bisherigen Ansatz und Schwierigkeiten damit zu beschreiben, aber lass nie das Ziel weg!

    Das kommt in Hilfsforen übrigens so häufig vor, dass sich ein feststehender Begriff dafür etabliert hat:
    Google: XY problem



  • SeppJ schrieb:

    Daher merke dir: Frage stets nach dem, was du erreichen möchtest! Nicht nach dem, was du denkst, wie die Lösung aussehen könnte. Jetzt haben wir beide viel Zeit und Arbeit verschwendet auf etwas, das gar nicht relevant war. Es ist ok (und oft auch gut), zu deinem Ziel auch deinen bisherigen Ansatz und Schwierigkeiten damit zu beschreiben, aber lass nie das Ziel weg!

    Das kommt in Hilfsforen übrigens so häufig vor, dass sich ein feststehender Begriff dafür etabliert hat:
    Google: XY problem

    Danke für den Hinweis. Das kenne ich leider auch selbst gut genug 🙄

    Das ist ein schönes Thema was man im beruflichen Leben weitergeben kann 😉


  • Mod

    SeppJ schrieb:

    C++ verbietet dieses Szenario (warum auch immer, wenn jemand den Grund weiß, bitte melden):

    A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

    Diese Beschränkung wurde auch vom CWG als überflüssig erkannt und durch CWG 1315 gelockert (und später noch einmal durch das Paper für auto Template Parameter). Das ist schon eineinhalb Jahre her--wie wär's mit einem aktuellen WD? 😉

    Clang kompiliert den Code. GCC hat diesbezüglich verschiedene bug reports. Der relevanteste wäre wohl 77781, welcher auch mittels sizeof demonstriert.

    Dann gäbe es bspw. 51155. Und tatsächlich,

    template <int a, int b>
    struct foo { };
    // due to 'a' not being used
    template <int a>
    struct foo<sizeof(a), a> { }; // not correct and compiles
    

    kompiliert GCC bis Version 4.7.4. Keine Ahnung, wer da bestehende DRs ignoriert und quasi eine regression herbeigeführt hat...


Anmelden zum Antworten