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.
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.