I'm getting a strange compiler error when trying to create constexpr std::string and std::vector objects:
#include <vector>
#include <string>
int main()
{
constexpr std::string cs{ "hello" };
constexpr std::vector cv{ 1, 2, 3 };
return 0;
}
The compiler complains that "the expression must have a constant value":
Am I missing something? I am using the latest Microsoft Visual Studio 2019 version: 16.11.4, and the reference (https://en.cppreference.com/w/cpp/compiler_support) states that constexpr strings and vectors are supported by this compiler version:
I have also tried the constexpr std::array, which does work. Could the issue have anything to do with the dynamic memory allocation associated with vectors?
Your program is actually ill-formed, though the error may be hard to understand. constexpr allocation support in C++20 is limited - you can only have transient allocation. That is, the allocation has to be completely deallocated by the end of constant evaluation.
So you cannot write this:
int main() {
constexpr std::vector<int> v = {1, 2, 3};
}
Because v's allocation persists - it is non-transient. That's what the error is telling you:
<source>(6): error C2131: expression did not evaluate to a constant
<source>(6): note: (sub-)object points to memory which was heap allocated during constant evaluation
v can't be constant because it's still holding on to heap allocation, and it's not allowed to do so.
But you can write this:
constexpr int f() {
std::vector<int> v = {1, 2, 3};
return v.size();
}
static_assert(f() == 3);
Here, v's allocation is transient - the memory is deallocated when f() returns. But we can still use a std::vector during constexpr time.
As #barry explained, you cannot create variables which requires dynamic allocation and which will be still available at runtime. I believe that this is explained by the following exclusion in :
An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:
https://eel.is/c++draft/expr.const#5.17
a new-expression ([expr.new]), unless the selected allocation function is a replaceable global allocation function ([new.delete.single], [new.delete.array]) and the allocated storage is deallocated within the evaluation of E;
Still you can do amazing things with this new features. For example join strings:
constexpr std::string join(std::vector<std::string> vec, char delimiter) {
std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
vec[0],
[&delimiter](const std::string& a, const std::string& b) {
return a + delimiter + b;
});
return result;
}
static_assert(join({ "one", "two", "three" }, ';') == "one;two;three"sv);
I've seen code that uses a const std::vector, however can't see why it wouldn't make more sense to simply use an std::array instead.
The values for the vector seem to be initialized at compile-time.
What is the benefit of a const std::vector?
Edit: The vector was not big, only a couple of strings, however I see that this may be one advantage.
const std::vector lets you have a "fixed sized array" whose size you only know at run time but still allows you to have all the benefits of a standard container. If you used a raw/smart pointer in your code you will need to manually pass the size of the array that it points to into the function(s) that need to know the size of the array.
The std::vector could be used with a large list of data, because it could use Dynamic Allocated Array to store values and before C++20 it's doesn't have a constexpr constructor. But std::array uses a raw C-Array and it could be used at compile time with the stack size restricted list of data. So:
std::array const is good for:
Where your data size is less than the stack size.
Where data locality is important.
You want your list at the compile time (before C++20).
std::vector const is good for:
Where your data size is large than the stack size.
It's quite common to see C++ code that expects references to vectors, sometimes const, something like this:
auto do_sum(std::vector<int> const& numbers) -> int {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
Even though the good intentions are not about not copying memory, this code require the caller to allocate a std::vector, even though the amount of value and the actual values might be known at compile time.
This might be fixed by using a span instead:
auto do_sum(std::span<int const> numbers) -> int {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
Now this code don't require the users to allocate a vector for the array, and might use std::array, or plain C arrays.
Also, sometimes you don't know what are the numbers of element the array can have, and might be determined at runtime. Consider this:
auto create_vector() -> std::vector<int> {
auto vec = std::vector<int>{};
if (/* runtime condition */) {
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
} else {
vec.push_back(4);
vec.push_back(5);
}
return vec;
}
int main() {
std::vector<int> const vec = create_vector();
}
As you can see here, as the vector is moved from scope to scope, the const-ness changes and is expressing the intent of the developer to only make it mutable in some initializing scopes.
Because the std::array needs you to specify the size as part of the type. By using std::vector the compiler can work that out for your dynamically.
This matters in maintenance situations as it prevents errors. You only add/remove a string from the initializer of the object and the vector will have the correct size automatically. If you use an array you need to add/remove the string and change the type of the array.
const std::vector<std::string> dataV = { "A", "B", "C" };
const std::array<std::string, 3> dataA = { "A", "B", "C" };
If I now modify these to only have two values.
// The vector will auto resize
const std::vector<std::string> dataV = { "A", "B"};
// This will still be of size three.
// This is not usually what you want.
const std::array<std::string, 3> dataA = { "A", "B"};
// The person modifying the code has to manually spot that and
// change the type to explicitly have two member array. Note
// It may not be as obvious as you think as the type may
// be hidden with a type alias of some description
using DataStore = std::array<std::string, 3>;
/// Lots of code:
DataStore dataA = { "A", "B"}; // Would you have spotted.
When built using C++17/C++20 x64 gcc/clang, the below snippet yields a compile error whereas de-referencing the iterator directly via *std::max_element(std::begin(arr), std::end(arr)) works fine. Any ideas as to why? I've also observed similar behavior with other standard algorithms that have become constexpr since C++20, e.g. std::upper_bound
int main()
{
constexpr std::array<int,5> arr = {1,2,3,4,5};
constexpr auto it = std::max_element(std::begin(arr), std::end(arr));
}
source>:11:73: error: '(((std::array<int, 5>::const_pointer)(& arr.std::array<int, 5>::_M_elems)) + 16)' is not a constant expression
11 | constexpr auto it = std::max_element(std::begin(arr), std::end(arr));
|
it has to store a pointer to the element of arr.
Since arr is not static, it's located on the stack, so its address can't be determined at compile-time.
It will work if you make arr static.
I want to optimize a little programm/library i'm writing and since 2 weeks i'm somewhat stuck and now wondering if what i had in mind is even possible like that.
(Please be gentle i don't have very much experience in meta-programming.)
My goal is of course to have certain computations be done by the compiler, so that the programmer - hopefully - only has to edit code at one point in the program and have the compiler "create" all the boilerplate. I do have a resonably good idea how to do what i want with macros, but it is wished that i do it with templates if possible.
My goal is:
Lets say i have a class that a using programmer can derive from. There he can have multiple incoming and outgoing datatypes that i want to register somehow so that the base class can do i'ts operations on them.
class my_own_multiply : function_base {
in<int> a;
in<float> b;
out<double> c;
// ["..."] // other content of the class that actually does something but is irrelevant
register_ins<a, b> ins_of_function; // example meta-function calls
register_outs<c> outs_of_function;
}
The meta-code i have up till now is this: (but it's not jet working/complete)
template <typename... Ts>
struct register_ins {
const std::array<std::unique_ptr<in_type_erasured>, sizeof...(Ts)> ins;
constexpr std::array<std::unique_ptr<in_type_erasured>, sizeof...(Ts)>
build_ins_array() {
std::array<std::unique_ptr<in_type_erasured>, sizeof...(Ts)> ins_build;
for (unsigned int i = 0; i < sizeof...(Ts); ++i) {
ins_build[i] = std::make_unique<in_type_erasured>();
}
return ins_build;
}
constexpr register_ins() : ins(build_ins_array()) {
}
template <typename T>
T getValueOf(unsigned int in_nr) {
return ins[in_nr]->getValue();
}
};
As you may see, i want to call my meta-template-code with a variable number of ins. (Variable in the sens that the programmer can put however many he likes in there, but they won't change at runtime so they can be "baked" in at compile time)
The meta-code is supposed to be creating an array, that is of the lengt of the number of ins and is initialized so that every field points to the original in in the my_own_multiply class. Basically giving him an indexable data structure that will always have the correct size. And that i could access from the function_base class to use all ins for certain functions wich are also iterable making things convinient for me.
Now i have looked into how one might do that, but i now am getting the feeling that i might not really be allowed to "create" this array at compile time in a fashion that allows me to still have the ins a and b be non static and non const so that i can mutate them. From my side they wouldn't have to be const anyway, but my compliler seems to not like them to be free. The only thing i need const is the array with the pointers. But using constexpr possibly "makes" me make them const?
Okay, i will clarify what i don't get:
When i'm trying to create an "instance" of my meta-stuff-structure then it fails because it expects all kinds of const, constexpr and so on. But i don't want them since i need to be able to mutate most of those variables. I only need this meta-stuff to create an array of the correct size already at compile time. But i don't want to sacrifice having to make everything static and const in order to achive this. So is this even possible under these kinds of terms?
I do not get all the things you have in mind (also regarding that std::unique_ptr in your example), but maybe this helps:
Starting from C++14 (or C++11, but that is strictly limited) you may write constexpr functions which can be evaluated at compile-time. As a precondition (in simple words), all arguments "passed by the caller" must be constexpr. If you want to enforce that the compiler replaces that "call" by the result of a compile-time computation, you must assign the result to a constexpr.
Writing usual functions (just with constexpr added) allows to write code which is simple to read. Moreover, you can use the same code for both: compile-time computations and run-time computations.
C++17 example (similar things are possible in C++14, although some stuff from std is just missing the constexpr qualifier):
http://coliru.stacked-crooked.com/a/154e2dfcc41fb6c7
#include <cassert>
#include <array>
template<class T, std::size_t N>
constexpr std::array<T, N> multiply(
const std::array<T, N>& a,
const std::array<T, N>& b
) {
// may be evaluated in `constexpr` or in non-`constexpr` context
// ... in simple man's words this means:
// inside this function, `a` and `b` are not `constexpr`
// but the return can be used as `constexpr` if all arguments are `constexpr` for the "caller"
std::array<T, N> ret{};
for(size_t n=0; n<N; ++n) ret[n] = a[n] * b[n];
return ret;
}
int main() {
{// compile-time evaluation is possible if the input data is `constexpr`
constexpr auto a = std::array{2, 4, 6};
constexpr auto b = std::array{1, 2, 3};
constexpr auto c = multiply(a, b);// assigning to a `constexpr` guarantees compile-time evaluation
static_assert(c[0] == 2);
static_assert(c[1] == 8);
static_assert(c[2] == 18);
}
{// for run-time data, the same function can be used
auto a = std::array{2, 4, 6};
auto b = std::array{1, 2, 3};
auto c = multiply(a, b);
assert(c[0] == 2);
assert(c[1] == 8);
assert(c[2] == 18);
}
return 0;
}
One of the interview questions asked me to "write the prototype for a C function that takes an array of exactly 16 integers" and I was wondering what it could be? Maybe a function declaration like this:
void foo(int a[], int len);
Or something else?
And what about if the language was C++ instead?
In C, this requires a pointer to an array of 16 integers:
void special_case(int (*array)[16]);
It would be called with:
int array[16];
special_case(&array);
In C++, you can use a reference to an array, too, as shown in Nawaz's answer. (The question asks for C in the title, and originally only mentioned C++ in the tags.)
Any version that uses some variant of:
void alternative(int array[16]);
ends up being equivalent to:
void alternative(int *array);
which will accept any size of array, in practice.
The question is asked - does special_case() really prevent a different size of array from being passed. The answer is 'Yes'.
void special_case(int (*array)[16]);
void anon(void)
{
int array16[16];
int array18[18];
special_case(&array16);
special_case(&array18);
}
The compiler (GCC 4.5.2 on MacOS X 10.6.6, as it happens) complains (warns):
$ gcc -c xx.c
xx.c: In function ‘anon’:
xx.c:9:5: warning: passing argument 1 of ‘special_case’ from incompatible pointer type
xx.c:1:6: note: expected ‘int (*)[16]’ but argument is of type ‘int (*)[18]’
$
Change to GCC 4.2.1 - as provided by Apple - and the warning is:
$ /usr/bin/gcc -c xx.c
xx.c: In function ‘anon’:
xx.c:9: warning: passing argument 1 of ‘special_case’ from incompatible pointer type
$
The warning in 4.5.2 is better, but the substance is the same.
There are several ways to declare array-parameters of fixed size:
void foo(int values[16]);
accepts any pointer-to-int, but the array-size serves as documentation
void foo(int (*values)[16]);
accepts a pointer to an array with exactly 16 elements
void foo(int values[static 16]);
accepts a pointer to the first element of an array with at least 16 elements
struct bar { int values[16]; };
void foo(struct bar bar);
accepts a structure boxing an array with exactly 16 elements, passing them by value.
& is necessary in C++:
void foo(int (&a)[16]); // & is necessary. (in C++)
Note : & is necessary, otherwise you can pass array of any size!
For C:
void foo(int (*a)[16]) //one way
{
}
typedef int (*IntArr16)[16]; //other way
void bar(IntArr16 a)
{
}
int main(void)
{
int a[16];
foo(&a); //call like this - otherwise you'll get warning!
bar(&a); //call like this - otherwise you'll get warning!
return 0;
}
Demo : http://www.ideone.com/fWva6
I think the simplest way to be typesafe would be to declare a struct that holds the array, and pass that:
struct Array16 {
int elt[16];
};
void Foo(struct Array16* matrix);
You already got some answers for C, and an answer for C++, but there's another way to do it in C++.
As Nawaz said, to pass an array of N size, you can do this in C++:
const size_t N = 16; // For your question.
void foo(int (&arr)[N]) {
// Do something with arr.
}
However, as of C++11, you can also use the std::array container, which can be passed with more natural syntax (assuming some familiarity with template syntax).
#include <array>
const size_t N = 16;
void bar(std::array<int, N> arr) {
// Do something with arr.
}
As a container, std::array allows mostly the same functionality as a normal C-style array, while also adding additional functionality.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
int arr2[5] = { 1, 2, 3, 4, 5 };
// Operator[]:
for (int i = 0; i < 5; i++) {
assert(arr1[i] == arr2[i]);
}
// Fill:
arr1.fill(0);
for (int i = 0; i < 5; i++) {
arr2[i] = 0;
}
// Check size:
size_t arr1Size = arr1.size();
size_t arr2Size = sizeof(arr2) / sizeof(arr2[0]);
// Foreach (C++11 syntax):
for (int &i : arr1) {
// Use i.
}
for (int &i : arr2) {
// Use i.
}
However, to my knowledge (which is admittedly limited at the time), pointer arithmetic isn't safe with std::array unless you use the member function data() to obtain the actual array's address first. This is both to prevent future modifications to the std::array class from breaking your code, and because some STL implementations may store additional data in addition to the actual array.
Note that this would be most useful for new code, or if you convert your pre-existing code to use std::arrays instead of C-style arrays. As std::arrays are aggregate types, they lack custom constructors, and thus you can't directly switch from C-style array to std::array (short of using a cast, but that's ugly and can potentially cause problems in the future). To convert them, you would instead need to use something like this:
#include <array>
#include <algorithm>
const size_t N = 16;
std::array<int, N> cArrayConverter(int (&arr)[N]) {
std::array<int, N> ret;
std::copy(std::begin(arr), std::end(arr), std::begin(ret));
return ret;
}
Therefore, if your code uses C-style arrays and it would be infeasible to convert it to use std::arrays instead, you would be better off sticking with C-style arrays.
(Note: I specified sizes as N so you can more easily reuse the code wherever you need it.)
Edit: There's a few things I forgot to mention:
1) The majority of the C++ standard library functions designed for operating on containers are implementation-agnostic; instead of being designed for specific containers, they operate on ranges, using iterators. (This also means that they work for std::basic_string and instantiations thereof, such as std::string.) For example, std::copy has the following prototype:
template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
OutputIterator result);
// first is the beginning of the first range.
// last is the end of the first range.
// result is the beginning of the second range.
While this may look imposing, you generally don't need to specify the template parameters, and can just let the compiler handle that for you.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
std::array<int, 5> arr2 = { 6, 7, 8, 9, 0 };
std::string str1 = ".dlrow ,olleH";
std::string str2 = "Overwrite me!";
std::copy(arr1.begin(), arr1.end(), arr2.begin());
// arr2 now stores { 1, 2, 3, 4, 5 }.
std::copy(str1.begin(), str1.end(), str2.begin());
// str2 now stores ".dlrow ,olleH".
// Not really necessary for full string copying, due to std::string.operator=(), but possible nonetheless.
Due to relying on iterators, these functions are also compatible with C-style arrays (as iterators are a generalisation of pointers, all pointers are by definition iterators (but not all iterators are necessarily pointers)). This can be useful when working with legacy code, as it means you have full access to the range functions in the standard library.
int arr1[5] = { 4, 3, 2, 1, 0 };
std::array<int, 5> arr2;
std::copy(std::begin(arr1), std::end(arr1), std::begin(arr2));
You may have noticed from this example and the last that std::array.begin() and std::begin() can be used interchangeably with std::array. This is because std::begin() and std::end() are implemented such that for any container, they have the same return type, and return the same value, as calling the begin() and end() member functions of an instance of that container.
// Prototype:
template <class Container>
auto begin (Container& cont) -> decltype (cont.begin());
// Examples:
std::array<int, 5> arr;
std::vector<char> vec;
std::begin(arr) == arr.begin();
std::end(arr) == arr.end();
std::begin(vec) == vec.begin();
std::end(vec) == vec.end();
// And so on...
C-style arrays have no member functions, necessitating the use of std::begin() and std::end() for them. In this case, the two functions are overloaded to provide applicable pointers, depending on the type of the array.
// Prototype:
template <class T, size_t N>
T* begin (T(&arr)[N]);
// Examples:
int arr[5];
std::begin(arr) == &arr[0];
std::end(arr) == &arr[4];
As a general rule of thumb, if you're unsure about whether or not any particular code segment will have to use C-style arrays, it's safer to use std::begin() and std::end().
[Note that while I used std::copy() as an example, the use of ranges and iterators is very common in the standard library. Most, if not all, functions designed to operate on containers (or more specifically, any implementation of the Container concept, such as std::array, std::vector, and std::string) use ranges, making them compatible with any current and future containers, as well as with C-style arrays. There may be exceptions to this widespread compatibility that I'm not aware of, however.]
2) When passing a std::array by value, there can be considerable overhead, depending on the size of the array. As such, it's usually better to pass it by reference, or use iterators (like the standard library).
// Pass by reference.
const size_t N = 16;
void foo(std::array<int, N>& arr);
3) All of these examples assume that all arrays in your code will be the same size, as specified by the constant N. To make more your code more implementation-independent, you can either use ranges & iterators yourself, or if you want to keep your code focused on arrays, use templated functions. [Building on this answer to another question.]
template<size_t SZ> void foo(std::array<int, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<int, 10> arr2;
foo(arr1); // Calls foo<5>(arr1).
foo(arr2); // Calls foo<10>(arr2).
If doing this, you can even go so far as to template the array's member type as well, provided your code can operate on types other than int.
template<typename T, size_t SZ>
void foo(std::array<T, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<float, 7> arr2;
foo(arr1); // Calls foo<int, 5>(arr1).
foo(arr2); // Calls foo<float, 7>(arr2).
For an example of this in action, see here.
If anyone sees any mistakes I may have missed, feel free to point them out for me to fix, or fix them yourself. I think I caught them all, but I'm not 100% sure.
Based on Jonathan Leffler's answer
#include<stdio.h>
void special_case(int (*array)[4]);
void anon(void){
int array4[4];
int array8[8];
special_case(&array4);
special_case(&array8);
}
int main(void){
anon();
return 0;
}
void special_case(int (*array)[4]){
printf("hello\n");
}
gcc array_fixed_int.c &&./a.out will yield warning:
array_fixed_int.c:7:18: warning: passing argument 1 of ‘special_case’ from incompatible pointer type [-Wincompatible-pointer-types]
7 | special_case(&array8);
| ^~~~~~~
| |
| int (*)[8]
array_fixed_int.c:2:25: note: expected ‘int (*)[4]’ but argument is of type ‘int (*)[8]’
2 | void special_case(int (*array)[4]);
| ~~~~~~^~~~~~~~~
Skip warning:
gcc -Wno-incompatible-pointer-types array_fixed_int.c &&./a.out