Constexpr Initialization of Array to Sort Contents

global initialization order with constexpr

[basic.start.static/2]:

Constant initialization is performed if a variable or temporary object with static or thread storage duration is constant-initialized. [...] Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. All static initialization strongly happens before ([intro.races]) any dynamic initialization.

So, "Is this code correct?": Yes, as my_array is constant initialized, and this happens before dynamic initialization (my_map).

(This quote is from the current draft standard, but this rule exists for C++14 as well)

Initializing an array with a constexpr?

Without seeing the definition of MyClass the problem is not quite clear.
I believe anyway that you want to get MyClass::_myVar initialized without
code to iteratively fill it with the MyClass::metaFunction() values.

You code suggests that MyClass::_myVar is a static class member. In that
case your initialization of the member is perfectly good C++11 as it stands.
The following program illustrates (GCC 4.6.3):

#include <iostream>

/* MyClass Version 1 */
template<unsigned int DIM>
struct MyClass
{
static constexpr unsigned int metaFunction(
const unsigned int k,
const unsigned int n,
const unsigned int dim);

static const unsigned int _myVar[2][3];
};

template<unsigned int DIM> inline constexpr
unsigned int MyClass<DIM>::metaFunction(
const unsigned int k,
const unsigned int n,
const unsigned int dim)
{
return (((n < dim) && (k < n)) ? (1<<(n-k)) : (0));
}

template<unsigned int DIM> const unsigned int MyClass<DIM>::_myVar[2][3] = {
{ metaFunction(0, 0, DIM),
metaFunction(0, 1, DIM),
metaFunction(0, 2, DIM)
},
{ metaFunction(1, 0, DIM),
metaFunction(1, 1, DIM),
metaFunction(1, 2, DIM)
}
};

template<unsigned int DIM> inline constexpr
unsigned int MyClass<DIM>::metaFunction(
const unsigned int k,
const unsigned int n,
const unsigned int dim)
{
return (((n < dim) && (k < n)) ? (1<<(n-k)) : (0));
}

using namespace std;

int main(void)
{
MyClass<3> mine;
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
cout << mine._myVar[i][j] << endl;
}
}
return 0;
}

This inclines me to think that MyClass::_myVar is not a static member -
although why this array of integer constants would not be static I am not sure.
If that is the case, then you can initialize the member in the default
constructor using the uniform initialization provision of C++11:

/* MyClass Version 2 */
template<unsigned int DIM>
struct MyClass
{
MyClass()
: _myVar{
{ MyClass::metaFunction(0, 0, DIM),
MyClass::metaFunction(0, 1, DIM),
MyClass::metaFunction(0, 2, DIM)
},
{ MyClass::metaFunction(1, 0, DIM),
MyClass::metaFunction(1, 1, DIM),
MyClass::metaFunction(1, 2, DIM)
}
}{}

static constexpr unsigned int metaFunction(
const unsigned int k,
const unsigned int n,
const unsigned int dim);

const unsigned int _myVar[2][3];
};

In neither case is the constexpr attribute of metaFunction actually
necessary for compilation. And if constexpr is removed
then /* MyClass Version 1*/ is also good for C++03.

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

How to write a constexpr quick sort in c++17?

The parameter array in the function QuickSort is not a constexpr variable, though it will be initialized with a constexpr argument array12, so you can't use it to initialize the constexpr variable leftSize.

In fact, a constexpr function can modify its parameters, so you can implement QuickSort as if it is a normal function:

#include <array>

template<typename T, std::size_t N>
constexpr void QuickSort(std::array<T, N> &array, std::size_t low, std::size_t high)
{
if (high <= low) return;
auto i = low, j = high + 1;
auto key = array[low];
for (;;) {
while (array[++i] < key) if (i == high) break;
while (array[--j] > key) if (j == low) break;
if (i >= j) break;

auto tmp = array[i];
array[i] = array[j];
array[j] = tmp;

}

auto tmp = array[low];
array[low] = array[j];
array[j] = tmp;

QuickSort(array, low, j - 1);
QuickSort(array, j + 1, high);
}

template<typename T, std::size_t N>
constexpr std::array<T, N> QuickSort(std::array<T, N> array)
{
QuickSort(array, 0, N - 1);
return array;
}

int main()
{
constexpr std::array<int, 6> array12{7, 9, 3, 6, 1, 19};
constexpr auto array13 = QuickSort(array12);
return 0;
}

Also note that since C++20, std::sort is already constexpr.

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.

Cannot construct constexpr array from braced-init-list

The compiler is complaining that the initializer of a.p is not a constant expression. It's failing §5.20/5.2:

if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value

In other words, only pointer values known to the linker are valid constants. (Also, in your example the pointer is dangling.)

The first static_assert doesn't trip this because p is discarded and the value of n is a constant expression. Constant expressions may have non-constant subexpressions.

This works:

static constexpr double arr[] = { 1.,2.,3. };
constexpr const_array<double> a{ arr };
static_assert( a.size() == 3 );

Credit to @Jarod42 for pointing out the issue in the comments.

Array constant not evaluating to constant even though only constexpr functions called in initialization

A recent version of GCC or Clang will tell you the evaluation that failed to yield a constant expression. See https://godbolt.org/z/adhafn8v7

The problem is the comparison:

array_[i] > array_[i + gap]

A comparison between unequal function pointers (other than to check whether or not they are equal) has an unspecified result, and therefore is not permitted inside a constant expression evaluation.

How to can a std::array class member be statically asserted to be sorted in c++11?

Here’s a proof of concept implementation that can be called directly on a std::array; making this more general (for other constexpr container types) is left as an exercise to the reader:

template <typename T, std::size_t N>
constexpr bool is_sorted(std::array<T, N> const& arr, std::size_t from) {
return N - from == 0 or (arr[from - 1] <= arr[from] and is_sorted(arr, from + 1));
}

template <typename T, std::size_t N>
constexpr bool is_sorted(std::array<T, N> const& arr) {
return N == 0 or is_sorted(arr, 1);
}


Related Topics



Leave a reply



Submit