C++ constexpr function to checksum an array - c++

Is there away to achieve the behavior shown in the example (non compiling) code below? I (think I) understand why it doesn't compile given that the required calls to std::initializer_list functions are not constexpr.
The goal is to be able to create an array from a constant initialiser list when an additional element is appended to the end that is the sum of the preceeding elements.
All the posts I found on initialising arrays at compile time required lots of complex recursive template function calls and all were related to generating sequences of numbers.
#include <initializer_list>
#include <array>
template <typename T> constexpr auto CheckSummedArray(const std::initializer_list<T> & i)
{
std::array<T, i.size() + 1> res;
std::copy(i.begin(), i.end(), res.begin());
auto cs = T();
for (auto r : i)
{
cs += r;
}
res[res.size() - 1] = cs;
return res;
}
constexpr auto testArray = CheckSummedArray<int>({1,2,3,4});
static_assert(testArray.size() == 5);
static_assert(testArray[0] == 1);
static_assert(testArray[4] == 9);

The issue is not the calls to the members of std::initializer_list, those functions are actually constexpr. The issue is that you are using the result of i.size() in a template parameter, but i is not a constant expression, since it's a function parameter.
You can solve this by making the argument an array type, and so you can deduce its size with a template parameter:
template <typename T, std::size_t N>
constexpr auto CheckSummedArray(T const(&i)[N])
{
std::array<T, N + 1> res{};
std::copy(i, i + N, res.begin());
res.back() = std::accumulate(i, i + N, 0);
return res;
}
Here's a demo.
I cleaned up the function a little by using an algorithm instead of a loop. If you're not using C++20, you don't have access to constexpr algorithms, so your copy and accumulate will need to be raw loops anyway.
for(std::size_t j = 0; j < N; ++j)
{
res[j] = i[j];
res.back() += i[j];
}
Here's a C++17 demo.

Related

How to initialize array elements with their indices

I would like to find an elegant way of initializing C++ array elements with their indices. I have a lot of code that looks like this:
static constexpr size_t ELEMENT_COUNT = 8;
MyObject x[ELEMENT_COUNT] = {{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}};
Where MyObject is effectively,
struct MyObject {
size_t mMyIndex;
MyObject(size_t myIndex) : mMyIndex(myIndex) {}
};
The problems should be already clear: when ELEMENT_COUNT changes, I have to adapt the initializer list, which feels very un-C++. And if ELEMENT_COUNT is, say, 1000, this becomes impractical.
Is something like the following possible in C++?:
MyObject mObjects[ELEMENT_COUNT] = initialize_array_with_indices<ELEMENT_COUNT>();
Does such a function like initialize_array_with_indices<N>() exist in the std library? Is it possible? Using std::array<> is an option, if that gets me further.
It is impossible to intialize a built-in array like this. Arrays can only be default-initialized, value-initialized or aggregate-initialized (with exception for string literals). The only one of these allowing to specify different values for the elements is aggregate initialization and that requires explicitly listing each element.
(There is one other exception specific to non-static array members of classes. They may be initialized by copy through implicitly defined constructors of the enclosing class. However that still doesn't allow writing an initializer like you want.)
So you have to use std::iota or a loop after the initialization.
If you use std::array instead of a built-in array, you can define it as
template<typename T, std::size_t N>
constexpr auto initialize_array_with_indices() {
return []<std::size_t... Is>(std::index_sequence<Is...>){
return std::array<T, N>{Is...};
}(std::make_index_sequence<N>());
}
To be used like
auto mObjects = initialize_array_with_indices<MyObject, ELEMENT_COUNT>();
The implementation above requires C++20. It can be written (slightly longer) for previous versions as well. Specifically before C++20 lambdas can't have explicit template parameters, so a helper function must be used instead (or a constexpr array of indices can be filled first with the approach below and then std::apply used on it to get the indices as a pack into the lambda). Also before C++17 it will require copy/move-constructibility of T.
An implementation that assumes that default-initialization of MyObject is possible and not undesirable would be much more straight-forward. (It would simply default-initialize a std::array and then loop through it to set the indices or use std::iota on it.)
Here is another way of doing this with both C++11 as well as C++20. Note that starting with C++17 we can do all this at compile time(if required). Additionally, I've made the converting constructor constexpr.
C++11 Version
This uses SFINAE:
struct C
{
int i;
//added constexpr here
constexpr C(int pi): i(pi)
{
}
};
/*
Version #1 : Used to end the recursion.
#tparam: destType : represents type of elements in the array to which we want to convert to. This parameter must be explicitly passed in angle brackets
#tparam: sourceType: represents type of elements in the array from which we want to convert. This parameter will be deduced using argument deduction
#tparam: sourceSize: represents size of the source array. This will also be deduced using deduction
#tparam: extractedTypes represents type of the values extracted by indexing and casting individual elments of sourceArray
#return: this function template returns an std::array with elements of type destType and size sourceSize
*/
template<typename destType, typename sourceType, std::size_t sourceSize, typename... extractedTypes>
constexpr typename std::enable_if<sizeof...(extractedTypes) == sourceSize, std::array<destType, sourceSize> >::type
cast_array(const std::array<sourceType, sourceSize> &sourceArray, const extractedTypes... extractedValues)
{
return std::array<destType, sourceSize>{{extractedValues...}};//use pack expansion
}
/*
Version 2 : Recursively called until sizeof...(Types) becomes same as sourceSize
#tparam: destType : represents type to be converted to which must be explicitly passed in angle brackets
#tparam: sourceType: represents type of elements in the array from which we want to convert. This will be deduced using argument deduction
#tparam: sourceSize: represents size of the source array. This will also be deduced using deduction
#tparam: extractedTypes represents type of the values extracted by indexing and casting individual elments of sourceArray
#return: this function template returns an std::array with elements of type destType and size sourceSize
*/
template<typename destType, typename sourceType, std::size_t sourceSize, typename... extractedTypes>
constexpr typename std::enable_if<sizeof...(extractedTypes) != sourceSize, std::array<destType, sourceSize> >::type
cast_array(const std::array<sourceType, sourceSize> &sourceArray, const extractedTypes... extractedValues)
{
//recursively call cast_array passing the sourceArray and extracted elements until all elements are extracted
return cast_array<destType>(sourceArray, extractedValues..., static_cast<destType>(sourceArray[sizeof...(extractedValues)]));
}//-----------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^->extract/pass elements index by index by casting them to destType
static constexpr size_t ELEMENT_COUNT = 8;
template<std::size_t N = ELEMENT_COUNT>
std::array<C, N> make_array()
{
std::array<int, ELEMENT_COUNT> tempArray{};
int count = 0;
for(auto &elem: tempArray)
{
elem = ++count;
}
return cast_array<C>(tempArray);
}
int main()
{
std::array<C, ELEMENT_COUNT> myArray = make_array();
//lets confirm if all objects have the expected value
for(const auto &elem: myArray)
{
std::cout << elem.i << std::endl;;
}
}
Working demo C++11
C++17 Version
With C++17, std::array<T, N>::begin is constexpr, so we can do all this at compile time(if needed). Here no changes have been made to the cast_array function template. Instead constexpr is added to make_array and myArray. So to avoid pasting the same code again and again, in the below code snippet I've only pasted the modified portion of the code. You can check out the full working example here.
//--------------------------------------vvvvvvvvv------->added constexpr here
template<std::size_t N = ELEMENT_COUNT> constexpr std::array<C, N> make_array()
{
std::array<int, ELEMENT_COUNT> tempArray{};
int count = 0;
for(auto &elem: tempArray)
{
elem = ++count;
}
return cast_array<C>(tempArray);
}
int main()
{
//note the constexpr here from C++17
constexpr std::array<C, ELEMENT_COUNT> myArray = make_array();
//lets confirm if all objects have the expected value
for(const auto &elem: myArray)
{
std::cout << elem.i << std::endl;;
}
}
C++17 demo
C++20 Version
Here we make use of requires. Since changes have been done to cast_array also so I will post the whole code here again(except the documentation part)
struct C
{
int i;
//added this constexpr
constexpr C(int pi): i(pi)
{
}
};
template<typename destType, typename sourceType, std::size_t sourceSize, typename... extractedTypes>
constexpr std::array<destType, sourceSize> cast_array(const std::array<sourceType, sourceSize> &sourceArray, const extractedTypes... extractedValues)
requires (sizeof...(extractedTypes) == sourceSize)
{
return std::array<destType, sourceSize>{{extractedValues...}};//use pack expansion
}
template<typename destType, typename sourceType, std::size_t sourceSize, typename... extractedTypes>
constexpr std::array<destType, sourceSize> cast_array(const std::array<sourceType, sourceSize> &sourceArray, const extractedTypes... extractedValues)
requires (sizeof...(extractedTypes) != sourceSize)
{
//recursively call cast_array passing the sourceArray and extracted elements until all elements are extracted
return cast_array<destType>(sourceArray, extractedValues..., static_cast<destType>(sourceArray[sizeof...(extractedValues)]));
}//-----------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^->extract/pass elements index by index by casting them to destType
static constexpr size_t ELEMENT_COUNT = 8;
//--------------------------------------vvvvvvvvv------->added constexpr here
template<std::size_t N = ELEMENT_COUNT> constexpr std::array<C, N> make_array()
{
std::array<int, ELEMENT_COUNT> tempArray{};
int count = 0;
for(auto &elem: tempArray)
{
elem = ++count;
}
return cast_array<C>(tempArray);
}
int main()
{
constexpr std::array<C, ELEMENT_COUNT> myArray = make_array();
for(const auto &elem: myArray)
{
std::cout << elem.i << std::endl;;
}
}
Working demo C++20
Note
If this is a one time thing then you can also use a lambda instead of a separate function template make_array. See demo with lambda
The answer from #user17732522 is fantastic and works in C++20. As they state, it only works for >=C++20, but with adaptations it can work for C++17 and earlier.
Here is a C++17 version, using a helper function:
template<typename T, std::size_t N, std::size_t... Is>
std::array<T, N> initialize_array_with_indices_helper(std::index_sequence<Is...>) {
return std::array<T, N>{Is...};
}
template<typename T, std::size_t N>
constexpr std::array<T,N> initialize_array_with_indices() {
return initialize_array_with_indices_helper<T, N>(std::make_index_sequence<N>());
}

`static_assert` on `std::initializer_list<T>::size` in a function

In my unit tests, I want a quick and (cleanish) dirty way to assign values to a static-size C-array from an initializer_list. I'm not a complete beast, so I want to static_assert that the sizes are the same. I wrote a helper function set_array to do this:
template <typename T, std::size_t N>
constexpr void set_array(T (&x)[N], std::initializer_list<T>&& list) {
assert(list.size() == N); // why can't I static_assert in C++17?
for (std::size_t i = 0; i < N; ++i)
x[i] = list.begin()[i];
}
with the intention of using it as set_array(foo, {1, 2, 3, 4}); with foo declared like int foo[4].
I'm using C++17, so std std::initializer_list<T>::size is constexpr, but as soon as I pass the list through a function call, I lose the privilege of treating it as constexpr since I can't constrain the function parameters to be constexpr.
This feels like it should have a simple solution that I'm not seeing. Sure, I could imagine some perverse metaprogramming games I could play to encode the size in a type, but this is a simple little helper that's supposed to make things clean and readable, and I don't want to go nuts.
Question: Is there a simple solution, or should I just live with the runtime assert? (Yes, I know that if I'm given a simple solution, I'm going to feel stupid for not having seen it myself.) Think I'm going about it the wrong way? That's fine, I'm open to suggestions and appreciate the criticism.
Details:
For completeness, here is the compiler error and version info. In Clang version 8.0.0-3 (That comes with Ubuntu clang-8) I get:
error: static_assert expression is not an
integral constant expression
static_assert(list.size() == N);
^~~~~~~~~~~~~~~~
And with GCC 8.3.0 I get a similar error, additionally telling me that list is not a constant expression.
The reason this fails even though size is constexpr is because list is not a constexpr variable so any member function calls on it will also not be constexpr.
All is not lost though. What you can do is use a std::array instead of a std::initializer_list which lets you even get rid of the static_assert like:
template <typename T, std::size_t N>
constexpr void set_array(T (&x)[N], std::array<T, N>&& list) {
for (std::size_t i = 0; i < N; ++i)
x[i] = list[i];
}
int main()
{
int arr[4];
set_array(arr, {1,2,3,4});
std::cout << arr[3];
}
If you tried using
set_array(arr, {1,2,3,4,5});
then you would get a compiler error like
main.cpp:12:16: note: candidate function [with T = int, N = 4] not viable: cannot convert initializer list argument to 'std::array<int, 4UL>'
constexpr void set_array(T (&x)[N], std::array<T, N>&& list) {
Arguments to functions are not constants.
This is legal in C++:
void foo( bool which ) {
std::initializer_list<int> a = {1,2,3};
std::initializer_list<int> b = {1,2,3,4};
int x[4];
std::initializer_list<int> c = which?a:b;
set_array(x, c);
}
try this:
template<class T>
struct block_deduction_t{using type=T;};
template<class T>
using block_deduction = typename block_deduction_t<T>::type;
template <typename T, std::size_t N>
constexpr void set_array(T (&x)[N], block_deduction<T const(&)[N]> list) {
for (std::size_t i = 0; i < N; ++i)
x[i] = list[i];
}
now this permits you to omit trailing elements, but they will be zero-initialized.
Live example.
Then again, this solution:
template <typename T, std::size_t N>
constexpr void set_array(T (&x)[N], T const(&list)[N]) {
for (std::size_t i = 0; i < N; ++i)
x[i] = list[i];
}
actually blocks under-sized right hand sides. So might be better.
Syntax exactly matches yours.
If you want a pretty error message, and for the right hand types to be converted to match the left hand side types:
template <typename T, std::size_t N, std::size_t M>
constexpr void set_array(T (&x)[N], block_deduction<T> const(&list)[M]) {
static_assert(M==N, "wrong number of elements");
for (std::size_t i = 0; i < N; ++i)
x[i] = list[i];
}
there are many variants.

C++ function design

I came across the following question in multiple occasions this year but I don't have a clear answer to it: say I want to design a function that accumulates or in general builds something. I would need to declare the initial accumulator value (or an empty object in general), the problem is that whether I should initialize this value or object inside the function arguments with default value or should I initialize this thing inside the function body?
An example would be the following piece of function that split an sequential container into N equal size pieces (precondition: the pieces are splittable).
Is it a okay to write it in the following form
template <typename T, std::size_t N>
array<T, N> equal_split(const T& x, array<T, N> result = {}) {
for (int i = 0; i < N; ++i)
std::copy(begin(x) + i * size(x) / 3, begin(x) + (i + 1) * size(x) / 3, std::back_inserter(result[i]));
return result;
}
or is it better to write it as
template <typename T, std::size_t N>
array<T, N> equal_split(const T& x) {
array<T, N> result = {};
for (int i = 0; i < N; ++i)
std::copy(begin(x) + i * size(x) / 3, begin(x) + (i + 1) * size(x) / 3, std::back_inserter(result[i]));
return result;
}
I would need to declare the initial accumulator value
If it is just an implementation detail, then hide it from interface.
if different initial values make sense, then you might add it in interface.
In your example, signature would be:
template <std::size_t N, typename Container>
array<Container, N> equal_split(const Container&);
Rename T to more meaningful Container
size_t N first, to not have to provide deducible Container
No default parameters, as initial value was just implementation detail.

Is it possible to set the value of elements in a constexpr array after declaration?

Is it possible to declare a const array (possibly constexpr) at one point, then define it at another place, one element at a time?
E.g.
extern constexpr int myArray[100];
myArray[0] = myConstexprFunction(0);
myArray[1] = myConstexprFunction(1);
// ...
myArray[100] = myConstexprFunction(100);
What I'm trying to do will need something like this. Maybe it's possible using things like: http://b.atch.se/posts/constexpr-counter/
But if this technique is going to be illegal in the next C++ standard (I hope not) I would like to use a safer one.
[EDIT] how about relaxing some requirements.. let's say that I want to do something like this:
constexpr int myConstExprFunction(int arg) { return arg + 100;}
// other code...
constexpr int a = myConstExprFunctionBegin(10);
constexpr int b = myConstExprFunction(20);
constexpr int c = myConstExprFunction(30);
constexpr int d = myConstExprFunctionEnd(40);
what I would like to have is that the myConstExprFunctionEnd is able to generate a final array with the values created by the previous functions.
Everything at compile time of course.
[EDIT2] C++11 solutions very welcomed
The requirement of constexpr of the recent C++ is very relaxed, so you could just write:
// requires C++17:
constexpr auto myArray = [] {
std::array<int, 100> result {};
for (size_t i = 0; i < 100; ++ i) {
result[i] = i * i;
}
return result;
}();
Note I used std::array<int, 100> instead of int[100] because a function cannot return a C array.
The above code requires C++17 for two reasons:
constexpr lambda
The mutable operator[] is not constexpr before C++17
Issue 1 can be easily worked-around using a separate constexpr function. Issue 2 can only be solved by defining your own array wrapper.
// requires C++14:
template <typename T, size_t n>
struct ConstexprArray {
T data[n];
constexpr ConstexprArray() : data{} {}
constexpr T& operator[](size_t i) { return data[i]; }
};
constexpr auto initialize_my_array() -> ConstexprArray<int, 100> {
ConstexprArray<int, 100> result {};
for (size_t i = 0; i < 100; ++ i) {
result[i] = i * i;
}
return result;
}
constexpr auto myArray = initialize_my_array();
Looking at your edit, I'd just answer no, because the compiler cannot transform a group of variables into an array. It just don't work that way. There isn't any construct in C++ that can take a bunch of declaration, delete them and replace it with another declaration. A source code preprocessor or generator might be able to permit the syntax you seek.
If you're interested in a solution that doesn't require external tooling, you can create a constexpr function that returns an array:
constexpr auto makeMyArray() {
std::array<int, 100> myArray{};
myArray[0] = myConstExprFunction(10);
myArray[1] = myConstExprFunction(20);
// ...
return myArray;
}
Then, initialize your array:
constexpr auto myArray = makeMyArray();
constexpr declares that it is possible to evaluate the value of the function or variable at compile time.
So the only way you could use it with array is like:
constexpr int myArray[100]{1 , 2 , 3 ,.........};
statements like
myArray[0] = myConstexprFunction(0);
can only be evaluated during runtime. So its not possible.
If you want to declare constexpr an array and initialize it's value using a constexpr function... the best I can think is wrap the array in a struct/array and initialize it via a delegate constructor.
The following is a full working C++14 example
#include <utility>
#include <iostream>
constexpr int myConstexprFunction (int i)
{ return i << 1; } // return 2*i
template <std::size_t S>
struct wrapArray
{
int const myWrappedArray[S];
template <int ... Is>
constexpr wrapArray (std::integer_sequence<int, Is...> const &)
: myWrappedArray { myConstexprFunction(Is)... }
{ }
constexpr wrapArray ()
: wrapArray(std::make_integer_sequence<int, S>())
{ }
};
int main ()
{
constexpr wrapArray<100> wa100;
for ( auto i : wa100.myWrappedArray )
std::cout << i << ", ";
std::cout << std::endl;
}
If you need a C++11 code, you have to implement a substitute for std::integer_sequence and for std::make_integer_sequence(). It's not difficult.
No.
constexpr variables must be "immediately initialised".

c++17 efficiently multiply parameter pack arguments with std::array elements

I want to efficiently multiply the arguments from a parameter pack with the elements of a std::array:
int index(auto... Is, std::array<int,sizeof...(Is)> strides)
{
// pseudo-code
// int idx = 0;
// for(int i = 0; i < sizeof...(Is); ++i)
// idx += Is[i] * strides[i];
// return idx;
}
I can't quite wrap my brain around this one. I started down the road of an index sequence, but I could figure out how to incorporate the summation.
I am using c++17, so fold expressions are fair game if they would simplify the code.
Thanks for any pointers.
EDIT: Clarified the pseudo-code. The only pseudo part is the expression Is[i] which refers to the i'th parameter pack argument.
T.C.'s answer below was perfect and here is my final code which is a member function:
unsigned int index(auto... indexes)
{
unsigned int idx = 0, i = 0;
(..., (idx += indexes * m_strides[i++]));
return idx;
}
As of this writing, the code compiles using gcc 6.3.0 with the -fconcepts flag, which brings in the Concept TS.
Using auto... indexes is shorthand for template<typename Args> f(Args... indexes). I tried to use an unsigned int concept for the arguments, but I couldn't get that to work.
The (...,) fold is the key element and expands to something like (if you could actually [] into the parameter pack):
idx += indexes[0] * m_strides[i++], idx += indexes[1] * m_strides[i++], etc.
That was the insight I was missing.
I can't get auto... to work, so I changed the signature of index.
You will need an auxiliary function (index_helper here) to use index_sequence, since it relies on template argument deduction to fill in the indices.
#include <array>
#include <cstdio>
template <typename... T, size_t... i>
// ^~~~~~~~~~~
// use deduction to make {i...} = {0, 1, 2, ..., n}
static int index_helper(const std::array<int, sizeof...(T)>& strides,
std::index_sequence<i...>,
T... Is)
{
return (0 + ... + (strides[i] * Is));
}
template <typename... T>
int index(const std::array<int, sizeof...(T)>& strides, T... Is) {
return index_helper(strides, std::make_index_sequence<sizeof...(T)>(), Is...);
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// generates {0, 1, 2, ..., n}
}
int main() {
printf("%d\n", index({1, 100, 100000, 1000}, 2, 3, 5, 7));
// 507302
}
If you can hammer down the argument pack into one single type that is cheap to copy/move, you can just make it into an array:
T arr[] = { static_cast<T>(Is)... }; // for some T, possibly common_type_t<decltype(Is)...>
Then you can just turn your pseudocode into real code.
If that's not feasible, a comma fold can be used:
int idx = 0, i = 0;
(..., (idx += Is * strides[i++]));
return idx;