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
Using Declaration in Variadic Template
C++ Trying to Swap Values in a Vector
Memory Allocation Profiling in C++
Problems Using Member Function as Custom Deleter with Std::Shared_Ptr
Why Do We Have Reinterpret_Cast in C++ When Two Chained Static_Cast Can Do Its Job
Why Isn't There an Operator[] for a Std::List
How to Effectively Kill a Process in C++ (Win32)
C++ View Types: Pass by Const& or by Value
Qt - Remove All Widgets from Layout
C++11 Variable Number of Arguments, Same Specific Type
Performance Wise, How Fast Are Bitwise Operators VS. Normal Modulus
Access Private Member Using Template Trick
C++ Local Variable Destruction Order
Sharing Precompiled Headers Between Projects in Visual Studio
Mock Non-Virtual Method C++ (Gmock)