constexpr begin of a std::array

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite
1












I am having trouble understanding why both gcc-8.2.0 and clang-7.0.0 reject the following code (live code here):



#include <array>

int main()

constexpr std::array<int,3> v1,2,3;
constexpr auto b = v.begin(); // error: not a constexpr
return 0;



with the error



error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)


According to en.cppreference.com, the begin() member function is declared constexpr. Is this a compiler bug?










share|improve this question























  • use .cbegin .
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago






  • 2




    @АлексейНеудачин makes no difference.
    – user2079303
    1 hour ago










  • @АлексейНеудачин begin() and cbegin() do the same thing on const objects.
    – Barry
    1 hour ago










  • so try auto b=... and then if it fails const . also you change auto to std::....::citerator
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago















up vote
6
down vote

favorite
1












I am having trouble understanding why both gcc-8.2.0 and clang-7.0.0 reject the following code (live code here):



#include <array>

int main()

constexpr std::array<int,3> v1,2,3;
constexpr auto b = v.begin(); // error: not a constexpr
return 0;



with the error



error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)


According to en.cppreference.com, the begin() member function is declared constexpr. Is this a compiler bug?










share|improve this question























  • use .cbegin .
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago






  • 2




    @АлексейНеудачин makes no difference.
    – user2079303
    1 hour ago










  • @АлексейНеудачин begin() and cbegin() do the same thing on const objects.
    – Barry
    1 hour ago










  • so try auto b=... and then if it fails const . also you change auto to std::....::citerator
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago













up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





I am having trouble understanding why both gcc-8.2.0 and clang-7.0.0 reject the following code (live code here):



#include <array>

int main()

constexpr std::array<int,3> v1,2,3;
constexpr auto b = v.begin(); // error: not a constexpr
return 0;



with the error



error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)


According to en.cppreference.com, the begin() member function is declared constexpr. Is this a compiler bug?










share|improve this question















I am having trouble understanding why both gcc-8.2.0 and clang-7.0.0 reject the following code (live code here):



#include <array>

int main()

constexpr std::array<int,3> v1,2,3;
constexpr auto b = v.begin(); // error: not a constexpr
return 0;



with the error



error: '(std::array<int, 3>::const_pointer)(& v.std::array<int,3>::_M_elems)' 
is not a constant expression (constexpr auto b = v.begin();)


According to en.cppreference.com, the begin() member function is declared constexpr. Is this a compiler bug?







c++ c++17 constexpr






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 1 hour ago









Barry

172k18292537




172k18292537










asked 1 hour ago









linuxfever

1,7381923




1,7381923











  • use .cbegin .
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago






  • 2




    @АлексейНеудачин makes no difference.
    – user2079303
    1 hour ago










  • @АлексейНеудачин begin() and cbegin() do the same thing on const objects.
    – Barry
    1 hour ago










  • so try auto b=... and then if it fails const . also you change auto to std::....::citerator
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago

















  • use .cbegin .
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago






  • 2




    @АлексейНеудачин makes no difference.
    – user2079303
    1 hour ago










  • @АлексейНеудачин begin() and cbegin() do the same thing on const objects.
    – Barry
    1 hour ago










  • so try auto b=... and then if it fails const . also you change auto to std::....::citerator
    – ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
    1 hour ago
















use .cbegin .
– ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
1 hour ago




use .cbegin .
– ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
1 hour ago




2




2




@АлексейНеудачин makes no difference.
– user2079303
1 hour ago




@АлексейНеудачин makes no difference.
– user2079303
1 hour ago












@АлексейНеудачин begin() and cbegin() do the same thing on const objects.
– Barry
1 hour ago




@АлексейНеудачин begin() and cbegin() do the same thing on const objects.
– Barry
1 hour ago












so try auto b=... and then if it fails const . also you change auto to std::....::citerator
– ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
1 hour ago





so try auto b=... and then if it fails const . also you change auto to std::....::citerator
– ÐÐ»ÐµÐºÑÐµÐ¹ Неудачин
1 hour ago













2 Answers
2






active

oldest

votes

















up vote
19
down vote



accepted










So let's sidestep std::array to make this a bit easier:



template <typename T, size_t N>
struct array
T elems[N];

constexpr T const* begin() const return elems;
;

void foo()
constexpr array<int,3> v1, 2, 3;
constexpr auto b = v.begin(); // error


constexpr array<int, 3> global_v1, 2, 3;
constexpr auto global_b = global_v.begin(); // ok


Why is b an error but global_b is okay? Likewise, why would b become okay if we declared v to be static constexpr? The problem is fundamentally about pointers. In order to have a constant expression that's a pointer, it has to point to one, known, constant thing, always. That doesn't really work for local variables without static storage duration, since they have fundamentally mutable address. But for function-local statics or globals, they do have one constant address, so you can take a constant pointer to them.




In standardese, from [expr.const]/6:




A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:



  • if the value is an object of class type, [...]

  • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and

  • [...]



b is none of those things in the second bullet, so this fails. But global_b satisfies the bolded condition - as would b if v were declared static.






share|improve this answer



























    up vote
    -3
    down vote













    Because standard iterators cannot be used in constexpr expressions, there is a proposal for it though which I think is available in c++17 check with c++17 compatible compiler






    share|improve this answer
















    • 1




      check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
      – Scheff
      49 mins ago











    Your Answer





    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52972533%2fconstexpr-begin-of-a-stdarray%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    19
    down vote



    accepted










    So let's sidestep std::array to make this a bit easier:



    template <typename T, size_t N>
    struct array
    T elems[N];

    constexpr T const* begin() const return elems;
    ;

    void foo()
    constexpr array<int,3> v1, 2, 3;
    constexpr auto b = v.begin(); // error


    constexpr array<int, 3> global_v1, 2, 3;
    constexpr auto global_b = global_v.begin(); // ok


    Why is b an error but global_b is okay? Likewise, why would b become okay if we declared v to be static constexpr? The problem is fundamentally about pointers. In order to have a constant expression that's a pointer, it has to point to one, known, constant thing, always. That doesn't really work for local variables without static storage duration, since they have fundamentally mutable address. But for function-local statics or globals, they do have one constant address, so you can take a constant pointer to them.




    In standardese, from [expr.const]/6:




    A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:



    • if the value is an object of class type, [...]

    • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and

    • [...]



    b is none of those things in the second bullet, so this fails. But global_b satisfies the bolded condition - as would b if v were declared static.






    share|improve this answer
























      up vote
      19
      down vote



      accepted










      So let's sidestep std::array to make this a bit easier:



      template <typename T, size_t N>
      struct array
      T elems[N];

      constexpr T const* begin() const return elems;
      ;

      void foo()
      constexpr array<int,3> v1, 2, 3;
      constexpr auto b = v.begin(); // error


      constexpr array<int, 3> global_v1, 2, 3;
      constexpr auto global_b = global_v.begin(); // ok


      Why is b an error but global_b is okay? Likewise, why would b become okay if we declared v to be static constexpr? The problem is fundamentally about pointers. In order to have a constant expression that's a pointer, it has to point to one, known, constant thing, always. That doesn't really work for local variables without static storage duration, since they have fundamentally mutable address. But for function-local statics or globals, they do have one constant address, so you can take a constant pointer to them.




      In standardese, from [expr.const]/6:




      A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:



      • if the value is an object of class type, [...]

      • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and

      • [...]



      b is none of those things in the second bullet, so this fails. But global_b satisfies the bolded condition - as would b if v were declared static.






      share|improve this answer






















        up vote
        19
        down vote



        accepted







        up vote
        19
        down vote



        accepted






        So let's sidestep std::array to make this a bit easier:



        template <typename T, size_t N>
        struct array
        T elems[N];

        constexpr T const* begin() const return elems;
        ;

        void foo()
        constexpr array<int,3> v1, 2, 3;
        constexpr auto b = v.begin(); // error


        constexpr array<int, 3> global_v1, 2, 3;
        constexpr auto global_b = global_v.begin(); // ok


        Why is b an error but global_b is okay? Likewise, why would b become okay if we declared v to be static constexpr? The problem is fundamentally about pointers. In order to have a constant expression that's a pointer, it has to point to one, known, constant thing, always. That doesn't really work for local variables without static storage duration, since they have fundamentally mutable address. But for function-local statics or globals, they do have one constant address, so you can take a constant pointer to them.




        In standardese, from [expr.const]/6:




        A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:



        • if the value is an object of class type, [...]

        • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and

        • [...]



        b is none of those things in the second bullet, so this fails. But global_b satisfies the bolded condition - as would b if v were declared static.






        share|improve this answer












        So let's sidestep std::array to make this a bit easier:



        template <typename T, size_t N>
        struct array
        T elems[N];

        constexpr T const* begin() const return elems;
        ;

        void foo()
        constexpr array<int,3> v1, 2, 3;
        constexpr auto b = v.begin(); // error


        constexpr array<int, 3> global_v1, 2, 3;
        constexpr auto global_b = global_v.begin(); // ok


        Why is b an error but global_b is okay? Likewise, why would b become okay if we declared v to be static constexpr? The problem is fundamentally about pointers. In order to have a constant expression that's a pointer, it has to point to one, known, constant thing, always. That doesn't really work for local variables without static storage duration, since they have fundamentally mutable address. But for function-local statics or globals, they do have one constant address, so you can take a constant pointer to them.




        In standardese, from [expr.const]/6:




        A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:



        • if the value is an object of class type, [...]

        • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a function, or a null pointer value, and

        • [...]



        b is none of those things in the second bullet, so this fails. But global_b satisfies the bolded condition - as would b if v were declared static.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 1 hour ago









        Barry

        172k18292537




        172k18292537






















            up vote
            -3
            down vote













            Because standard iterators cannot be used in constexpr expressions, there is a proposal for it though which I think is available in c++17 check with c++17 compatible compiler






            share|improve this answer
















            • 1




              check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
              – Scheff
              49 mins ago















            up vote
            -3
            down vote













            Because standard iterators cannot be used in constexpr expressions, there is a proposal for it though which I think is available in c++17 check with c++17 compatible compiler






            share|improve this answer
















            • 1




              check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
              – Scheff
              49 mins ago













            up vote
            -3
            down vote










            up vote
            -3
            down vote









            Because standard iterators cannot be used in constexpr expressions, there is a proposal for it though which I think is available in c++17 check with c++17 compatible compiler






            share|improve this answer












            Because standard iterators cannot be used in constexpr expressions, there is a proposal for it though which I think is available in c++17 check with c++17 compatible compiler







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 1 hour ago









            Ogunleye Ayowale Pius

            114




            114







            • 1




              check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
              – Scheff
              49 mins ago













            • 1




              check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
              – Scheff
              49 mins ago








            1




            1




            check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
            – Scheff
            49 mins ago





            check with c++17 compatible compiler This is what OP did. You can see it if you follow OP's here link. (She/he has explicitly set -std=c++17 in the options of godbolt.org.)
            – Scheff
            49 mins ago


















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52972533%2fconstexpr-begin-of-a-stdarray%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            What does second last employer means? [closed]

            Installing NextGIS Connect into QGIS 3?

            One-line joke