c++memoryc++20stdvector

C++20 compile time retrieve size of a vector


I have a question regarding to the compile time retrieving size of a vector in C++20. Based on C++20 it is possible to create in compile time a vector or a string in the scope of a function.

There is the following piece of code

#include <iostream>
#include <vector>
#include <array>

consteval auto copyVecToArray(){
    std::vector<int> vec{1,2,3,4,5,6,7};
    std::array<int,vec.size()> arr;
    std::copy(std::begin(vec),std::end(vec),std::begin(arr));
    return arr;
}
int main() {
   constexpr auto value = copyVecToArray();
   for(auto el : value){
        std::cout << el << std::endl;
   }
}

Demo which is failed with following compilation error

> <source>:7:28:   in 'constexpr' expansion of
> 'vec.std::vector<int>::size()'
> /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_vector.h:993:32:
> error: the value of 'vec' is not usable in a constant expression   993
> |       { return size_type(this->_M_impl._M_finish -
> this->_M_impl._M_start); }
>       |                          ~~~~~~^~~~~~~ <source>:6:22: note: 'vec' was not declared 'constexpr'
>     6 |     std::vector<int> vec{1,2,3,4,5,6,7};
>       |                      ^~~ <source>:7:28: note: in template argument for type 'long unsigned int'
>     7 |     std::array<int,vec.size()> arr;
>       |                    ~~~~~~~~^~ <source>:8:55: error: no matching function for call to 'begin(int&)'
>     8 |     std::copy(std::begin(vec),std::end(vec),std::begin(arr));
>       |

But if I change a bit the code above and return the size of the vector from a consteval function this successfully compiles.

#include <iostream>
#include <vector>
#include <array>
consteval auto getVec(){
    std::vector<int> vec{1,2,3,4,5,6,7};
    return vec;
}
consteval auto getSize(){
    return getVec().size();
}
consteval auto copyVecToArray(){
    std::array<int,getVec().size()> arr;
    auto vec = getVec();
    std::copy(std::begin(vec),std::end(vec),std::begin(arr));
    return arr;
}
int main() {
   constexpr auto value = copyVecToArray();
   for(auto el : value){
        std::cout << el << std::endl;
   }
}

My question is why using consteval function to retrieve size is ok and not using directly the std::vector::size() method.

Demo 2


Solution

  • Local variables even in consteval functions are not constant expressions because they are able to depend on the values of the function’s parameters. It breaks the type system to let them be such. Nor can you work around this (even when the parameter values aren’t needed) by declaring the std::vector constexpr, since only empty vectors can be complete constant expressions (for deeply technical reasons). Thus the compute-twice trick.