Vitali
Vitali

Reputation: 3695

How to convert template-sized array initialization to constexpr initialization?

Here's the loop. Basically generates a certain number of points along the circumference of the circle. The points array is obviously constant & can be computed at compile-time, but I can't seem to figure out a way to hoist it into a constexpr.

#include <array>
#include <cmath>

template <std::size_t Len>
class Circle {
public:
    Circle() {
        for (int i = 0; i < Len; i++) {
            float x = (float)std::cos(2 * M_PI * i / (Len - 1));
            float y = (float)std::sin(2 * M_PI * i / (Len - 1));
            points[i * 3] = x;
            points[i * 3 + 1] = y;
            points[i * 3 + 2] = 0;
        }
     }
 private:
     std::array<float, Len * 3> points;
 };

Upvotes: 1

Views: 260

Answers (2)

user541686
user541686

Reputation: 210765

They're not guaranteed to be strictly accurate, but they might be good enough for your purposes.

I just used the Taylor-series approximations. Add constexpr and see if they work.

long double sin2r(long double const r, long double const t, long double const tn, unsigned long long k)
{
    return tn == 0 ? r : sin2r(r + ((k / 2) % 2 ? -1 : +1) * tn, t, tn * t * t / ((k + 1) * (k + 2)), k + 2);
}

long double cos2r(long double const r, long double const t, long double const tn, unsigned long long k)
{
    return tn == 0 ? r : cos2r(r + ((k / 2) % 2 ? -1 : +1) * tn, t, tn * t * t / ((k + 1) * (k + 2)), k + 2);
}

long double sin2(long double const t)
{
    return sin2r(0, t, t, 1);
}

long double cos2(long double const t)
{
    return cos2r(0, t, 1, 0);
}

Upvotes: 3

Billy ONeal
Billy ONeal

Reputation: 106609

First of all, a constexpr function is not necessarily evaluated at compile time. There are cases where the compiler must do this (e.g. if the thing is used as a compile time constant); but the standard doesn't require such a thing. (In theory, a compiler might want to do this if storing the generation code and running it once at startup was trivial and used less space than storing the calculated value of the constexpr)

Second, your example is not possible to make constexpr. The standard requires any constexpr function to only call other constexpr functions, and be of the form return expression;. Your example meets neither qualification, because you depend on sin and cos (which are not constexpr functions), and you require a loop, which is not of the form return expression;.

constexpr is not designed for optimization; it is designed to allow you to calculate compile time constants (e.g. so that you could use the result as the size of a stack allocated array).

Upvotes: 2

Related Questions