array.size() als Template-Parameter



  • Hallo, ich habe folgenden Code:

    #include <bitset>
    #include <array>
    #include <iostream>
    
    template<size_t N>
    void func(const std::array<bool,N>& arr)
    {
      std::bitset<arr.size()> bits(0);
      for(size_t i=0; i<N; ++i)
        bits[i] = arr[i];
      std::cout << bits << std::endl;
    }
    
    int main()
    {
      std::array<bool,15> myarray = {true, false, false, false, true, true, false};
      func(myarray);
    }
    

    Dieser kompiliert problemlos mit dem GNU Compiler. Der Microsoft Compiler in Visual Studio 2015 und Clang++ beschweren sich jedoch beide über Zeile 8. Das Template-Argument arr.size() sei keine Compiletime-constant-expression (constexpr).

    Hier steht jedoch das Gegenteil:
    http://www.cplusplus.com/reference/array/array/size/

    Wer hat Recht?



  • Beklagen hilft nicht 😉 Ein workaround schon eher:

    #include <bitset>
    #include <array>
    #include <iostream>
    
    template < class T >
    struct size_from_array;
    
    template < typename T, std::size_t N >
    struct size_from_array< std::array<T,N> >
    {
        enum { size = N };
    };
    
    template < std::size_t N >
    void func(const std::array<bool,N>& arr)
    {
      std::bitset< size_from_array< std::array<bool,N> >::size > bits(0);
      for(size_t i=0; i<N; ++i)
        bits[i] = arr[i];
      std::cout << bits << std::endl;
    }
    
    int main()
    {
      std::array<bool,15> myarray = {true, false, false, false, true, true, false};
      func(myarray);
    }
    

    mfg Torsten


  • Mod

    Eine ähnliche Frage habe ich schonmal beantwortet: http://stackoverflow.com/a/36432725/3647361

    Hier hat GCC Recht, da size als constexpr deklariert ist und einfach eine Konstante zurückgibt - ob das Objekt Argument überhaupt const ist, ist irrelevant, da es innerhalb der Funktion nicht verwendet wird.
    Das hängt aber natürlich davon ab, wie aktuell deine Implementierungen alle sind: Clang trunk kompiliert deinen Code.



  • Hallo, kreativer Workaround. Mich würde aber trotzdem interessieren, ob der Fehler tatsächlich beim Compiler oder bei mir liegt. Ich bin vorsichtig geworden Compiler zu beschuldigen, da sie erfahrungsgemäß tatsächlich fast immer richtig liegen. 😉



  • Naja, wenn wir mal davon ausgehen, dass die angegebene Referenz korrekt ist, dann kommt es drauf an, ob das Beispiel C++11 oder C++14 ist. Für C++14 wäre Dein code dann korrekt. Nur, was nützt es Dir, wenn der Code korrekt ist? 😉



  • @Arcoth: Danke für die klare Einschätzung. Hier läuft noch Clang 3.7.1, da ist der Bug wohl noch drin, der in 3.9.0 gefixt ist. Wieder ein Grund mehr auf den Microsoft Compiler einzuprügeln 😉 (Bitte nicht zu ernst nehmen)


  • Mod

    Torsten Robitzki schrieb:

    Beklagen hilft nicht 😉 Ein workaround schon eher:

    #include <bitset>
    #include <array>
    #include <iostream>
    
    template < class T >
    struct size_from_array;
    
    template < typename T, std::size_t N >
    struct size_from_array< std::array<T,N> >
    {
        enum { size = N };
    };
    
    template < std::size_t N >
    void func(const std::array<bool,N>& arr)
    {
      std::bitset< size_from_array< std::array<bool,N> >::size > bits(0);
      for(size_t i=0; i<N; ++i)
        bits[i] = arr[i];
      std::cout << bits << std::endl;
    }
    
    int main()
    {
      std::array<bool,15> myarray = {true, false, false, false, true, true, false};
      func(myarray);
    }
    

    mfg Torsten

    Ja..... oder man benutzt einfach N . 😮



  • Torsten Robitzki schrieb:

    Naja, wenn wir mal davon ausgehen, dass die angegebene Referenz korrekt ist, dann kommt es drauf an, ob das Beispiel C++11 oder C++14 ist. Für C++14 wäre Dein code dann korrekt.

    Warum wäre der Code für C++11 nicht korrekt? Ich habe mit -std=c++11 kompiliert.



  • Arcoth schrieb:

    Ja..... oder man benutzt einfach N . 😮

    Ähh, .... ja! 😉 Zumindest im gg. Beispiel.



  • Mr Train schrieb:

    Warum wäre der Code für C++11 nicht korrekt? Ich habe mit -std=c++11 kompiliert.

    Sorry, habe mich verguckt. Müsste natürlich für C++11 und C++14 funktionieren.


  • Mod

    Mr Train schrieb:

    Torsten Robitzki schrieb:

    Naja, wenn wir mal davon ausgehen, dass die angegebene Referenz korrekt ist, dann kommt es drauf an, ob das Beispiel C++11 oder C++14 ist. Für C++14 wäre Dein code dann korrekt.

    Warum wäre der Code für C++11 nicht korrekt?

    Das wüsste ich auch gern, denn AFAICS ist der Code auch in C++11 korrekt (N3337 zeigt size als constexpr ).


Anmelden zum Antworten