Create N-element constexpr array in C++11
In C++14 it can be easily done with a constexpr
constructor and a loop:
#include <iostream>
template<int N>
struct A {
constexpr A() : arr() {
for (auto i = 0; i != N; ++i)
arr[i] = i;
}
int arr[N];
};
int main() {
constexpr auto a = A<4>();
for (auto x : a.arr)
std::cout << x << '\n';
}
c++11 way of returning an array of unknown number of elements
Trailing return type should do the job:
struct DataBinding {
static constexpr auto getRawBindings()
-> decltype(
asConstArray(
DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
DEF_BINDING(float, areaProp, areaParam) //BindingInfo constexpr object
//(...)
)
)
{
return asConstArray(
DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
DEF_BINDING(float, areaProp, areaParam) //BindingInfo constexpr object
//(...)
);
}
};
To avoid the repetition, MACRO might help:
#define RETURN(Expr) decltype(Expr) { return Expr; }
and then
struct DataBinding {
static constexpr auto getRawBindings()
-> RETURN(
asConstArray(
DEF_BINDING(int, stateProp, stateParam), //BindingInfo constexpr object
DEF_BINDING(float, areaProp, areaParam) //BindingInfo constexpr object
//(...)
)
)
};
How to generate an inline constexpr plain array of array in c++17
Just use std::array<std::span<int>, N>
, which is a fixed size array of spans of different sizes. To generate this, use an std::index_sequence
Header:
constexpr std::size_t size_of_A = 500;
extern const std::array<const std::span<const int>, size_of_A>& A;
Implementation:
constexpr std::size_t size_of_B_in_A(std::size_t i) { return i%10+1;}
constexpr int f(std::size_t i, std::size_t j) {return static_cast<int>(i%(j+1));}
template <int I, int N>
struct B
{
std::array<int,N> arr;
explicit constexpr B()
{
for (int j = 0; j < N; j++)
arr[j] = f(I, j);
}
constexpr operator const std::span<const int>() const {return {arr};}
};
template<class index_sequence>
class BGen;
template<std::size_t... I>
struct BGen<std::integer_sequence<std::size_t,I...>> {
static constexpr std::tuple<B<I, size_of_B_in_A(I)>...> bs{};
static constexpr std::array<const std::span<const int>, sizeof...(I)> A {std::get<I>(bs)...};
};
const std::array<const std::span<const int>, size_of_A>& A
= BGen<decltype(std::make_index_sequence<size_of_A>{})>::A;
Usage:
int main()
{
for (unsigned i = 0; i < A.size() ; i++)
{
for (unsigned j = 0; j < A[i].size(); j++)
{
std::cout << A[i][j];
}
}
}
http://coliru.stacked-crooked.com/a/d68b0e9fd6142f86
However, stepping back: This solution is NOT the normal way to go about solving this problem. Since it's all constexpr
, this is all data not code. Ergo, the most performant solution is two programs. One generates the data and saves it to a file that ships with (inside?) your program. Then your program simply maps the file into memory, and uses the data directly.
Populate An Array Using Constexpr at Compile-time
Ignoring ALL the issues, indices to the rescue:
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
template<unsigned... Is>
constexpr Table MagicFunction(seq<Is...>){
return {{ whichCategory(Is)... }};
}
constexpr Table MagicFunction(){
return MagicFunction(gen_seq<128>{});
}
Live example.
populating a constexpr array using C++17
This is a restriction in C++ until C++20, see Permitting trivial default initialization in constexpr contexts: You have to initialize all variables inside of a constexpr
function. The Standard gives the following example:
C++17
constexpr int uninit() {
int a; // error: variable is uninitialized
return a;
}
C++20
constexpr int uninit() {
struct { int a; } s;
return s.a; // error: uninitialized read of s.a
}
Note that the initialization itself is OK in C++20. Reading the indeterminate value (inside the "uninitialized" object) is not OK.
To fix your issue, initialize the array or switch to C++20:
static constexpr std::array<int, N> getArr()
{
std::array<int, N> a{}; // now initialized!
for (auto idx = 0; idx < a.size(); ++idx)
{
a[idx] = idx * idx;
}
return a;
}
constexpr array initialisation
Like said here
Because
std::array<T, N>
is an aggregate, it can be initialized as a constexpr if and only if the underlying typeT
has a constexpr constructor (when presented with each initializer you provide).
As std::vector
doesn't have a constexpr constructor (yet), this will not work.
So with pre-C++20 this will not work with dynamic size STL containers. No solution or quick fix. Don't get your hopes up.
The alternative is to design your own constexpr fixed-max-size Vector
class. e.g.
template <typename T, std::size_t N>
class Vector {
private:
T values[N]{};
public:
std::size_t size{ 0 };
constexpr bool empty() const noexcept { return size == 0; }
constexpr void clear() noexcept { size = 0; }
constexpr T* begin() noexcept { return &values[0]; }
constexpr T* end() noexcept { return &values[size]; }
constexpr T const* cbegin() const noexcept { return &values[0]; }
constexpr T const* cend() const noexcept { return &values[size]; }
constexpr T& back() noexcept { return values[size - 1]; }
constexpr T operator[] (int const loc) const noexcept { return values[loc]; }
constexpr T& operator[] (int const loc) noexcept { return values[loc]; }
constexpr void push_back(T const& value) noexcept { values[size++] = value; }
constexpr void resize(int const newSize) noexcept {
auto const diff = newSize - size;
if (diff > 0) memset(end(), 0, diff * sizeof(T));
size = newSize;
}
};
This is one I use sometimes... you need to add a initializer_list
constructor.
edit: Quick test... this seems to compile.
#include <array>
template <typename T, std::size_t N>
class Vector {
private:
T values[N]{};
public:
std::size_t size{ 0 };
constexpr Vector(std::initializer_list<T> il) noexcept
: size(std::distance(std::cbegin(il), std::cend(il)))
{
std::size_t i = 0;
for(auto it = std::cbegin(il); it != std::cend(il); ++it) {
values[i++]=*it;
}
}
};
struct SomeStruct {
Vector<int,5> vec;
};
int main() {
[[maybe_unused]]constexpr std::array<SomeStruct, 2> arr {
SomeStruct {
.vec = {
1, 2
}
},
SomeStruct {
.vec = {
3, 4, 5
}
}
};
}
Using `constexpr` with array initialization
Static constexpr data member declarations aren't definitions in C++11/14, therefore you cannot odr-use prim
.
To work around it, put the following statement somewhere in your cpp file as you would do with any other non-constexpr static data member:
constexpr const float bar::prim[4];
In other terms, this returns an undefined reference:
struct bar {
static constexpr const float prim[4] = {2, 3, 5, 7};
};
int main() {
auto *foo = bar::prim;
}
This doesn't:
struct bar {
static constexpr const float prim[4] = {2, 3, 5, 7};
};
constexpr const float bar::prim[4];
int main() {
auto *foo = bar::prim;
}
Because in the second case you are actually defining prim
other than declaring it and thus you can get its address, use it by means of a reference, and so on...
Is it possible to initialize constexpr std::array member in a programtic way
You don't need anything special, constexpr
function requirements are very relaxed these days:
#include <iostream>
#include <array>
template <int N> constexpr std::array<int, N> first_n_fibs()
{
std::array<int, N> ret{};
ret[0] = 0;
if (N == 1) return ret;
ret[1] = 1;
for (int i = 2; i < N; i++)
ret[i] = ret[i-2] + ret[i-1];
return ret;
}
int main()
{
constexpr auto a = first_n_fibs<3>();
}
(try it live)
std::array
constructors are not constexpr
Apparently it has no user-defined constructors at all, so nothing stops its construction from being constexpr
.
Related Topics
Getting Size of Array from Pointer C++
C/C++: Force Bit Field Order and Alignment
How to Calculate Execution Time of a Code Snippet in C++
What Is the Efficient Way to Count Set Bits At a Position or Lower
Unresolved External Symbol _Imp_Fprintf and _Imp_Iob_Func, Sdl2
Is There Any Overhead to Declaring a Variable Within a Loop - C++
C++ Syntax For Explicit Specialization of a Template Function in a Template Class
What's the Difference Between a Header File and a Library
What Requirements Must Std::Map Key Classes Meet to Be Valid Keys
No Matching Function - Ifstream Open()
Is This Behavior of Vector::Resize(Size_Type N) Under C++11 and Boost.Container Correct
Create N-Element Constexpr Array in C++11
Why Is Address Zero Used For the Null Pointer
Deprecated Header ≪Codecvt≫ Replacement
C++: Print Out Enum Value as Text