Noam Rodrik Noam Rodrik - 25 days ago 4
C++ Question

strange behavior of constexpr

I'm trying to understand constexpr as best as I can. However, i've found a problem that I can't really explain (I don't understand the compiler's decisions on this code-piece). This code has been compiled with the -O3 flag on X86-64 gcc 7.2, with C++17 as it's std flag (I've been using godbolt.org for this compilation)

Taking this code:

#include <stdlib.h>
#include <stdio.h>

template <size_t N>
class constexpr_sum_array_compile_time
{
public:
inline constexpr constexpr_sum_array_compile_time ()
{
start_arr();
sum();
}

inline constexpr void start_arr()
{
for (int i = 0; i<N; ++i)
{
m_arr[i] = i;
}
}

inline constexpr void sum()
{
m_sum = 0;

for (int i = 0; i<N; ++i)
{
m_sum += m_arr[i];
}
}

constexpr int sum_res()
{
return this->m_sum;
}

private:
int m_arr[N];
int m_sum = 0;
};

#define NUMBER (4)

int main()
{
return constexpr_sum_array_compile_time<NUMBER>().sum_res();
}


In a nutshell, this is a constexpr class that creates an array with a given size, and then sums an array with incremental values (arr[0] = 0, arr[1] = 1, arr[2] = 2... arr[n] = n) on compile_time (at least thats what I want it to do).
If the "NUMBER" define is in range: { 0 <= NUMBER <= 4 or 8 <= NUMBER <= 71 }
Then this class is optimized completely and returns only a single value (Like expected)

However! If NUMBER is in range: { 5 <= NUMBER <= 7 or NUMBER >= 72}, the compiler ISN'T ABLE to optimize the return value.
How come? What's so special about these values?
You can check the optimizations over at godbolt.org, it shows raw assembly as it's being compiled.

SOLVED



It seems like I needed to create a variable that holds the keyword of constexpr in order to allow the compiler to calculate it in compile time. The new code is:

#include <stdlib.h>
#include <stdio.h>

template <size_t N>
class constexpr_sum_array_compile_time
{
public:
inline constexpr constexpr_sum_array_compile_time() : m_arr(), m_sum(0)
{
start_arr();
sum();
}

inline constexpr void start_arr()
{
for (int i = 0; i<N; ++i)
{
m_arr[i] = i;
}
}

inline constexpr void sum()
{
m_sum = 0;

for (int i = 0; i<N; ++i)
{
m_sum += m_arr[i];
}
}

inline constexpr int sum_res()
{
return this->m_sum;
}

private:
int m_arr[N];
int m_sum;
};

#define NUMBER (6)

int main()
{
constexpr auto res = constexpr_sum_array_compile_time<NUMBER>().sum_res();
return res;
}


Now no matter what I write in NUMBER (even 100000) it shows the value optimized and calculated at compile-time!

Answer Source

Contrary to your expectation your class is not constexpr (and not used in constexpr expression).

constexpr auto res = constexpr_sum_array_compile_time<NUMBER>().sum_res();

would show you the different errors you have.

So what you observe with assembly is just regular optimization.