Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use folding in constexpr function c++

Tags:

c++

constexpr

I created the following constexpr function:

template <unsigned int M, unsigned int N, unsigned int P, typename T, T... ints>
constexpr int computeGeneratorCount(std::integer_sequence<T, ints...> int_seq)
{
    int count = 0;
    (([count] {
        int i = ints / N / P;
        int j = (ints - i * N * P) / P;
        int k = (ints - i * N * P - j * P);
        Plane pl = Plane(i, j, k);
        if (pl.containsPoint(0, 0))
            count++;
    }(), ...);

    return count;
}

Now I am trying to call this function like this:

static constexpr int generatorCount = computeGeneratorCount<11, 11, 4, std::size_t>(std::make_index_sequence<11 * 11 * 4>{});

but I am getting multiple compilation errors.

The class Plane is as follows:

class Plane
{
private:
    int m_orient;
    int m_row, m_col;

 public:
     constexpr Plane(int row, int col, int orient) : m_row(row), m_col(col), m_orient(orient) {}

     bool containsPoint(int x, int y) const {
         return true;
     }
 }

The function containsPoint is in reality more complex but I am only giving here a minimum reproducible example.

I am only now learning compile time computations. Can anyone give me a hint in the right direction?

Thank you!

like image 815
Cristi Avatar asked Sep 14 '26 07:09

Cristi


1 Answers

If you begin with compile time computations, I would suggest to begin with the easy way, i.e. use the fact that you can do compile time computations almost as "ordinary" code. For instance, you could have

template <unsigned int M, unsigned int N, unsigned int P>
constexpr int computeGeneratorCount () {
    std::size_t T = M*N*P;
    int count = 0;
    for (std::size_t t=0; t<T; t++) {
        int i = t / N / P;
        int j = (t - i * N * P) / P;
        int k = (t - i * N * P - j * P);
        Plane pl {i, j, k};
        if (pl.containsPoint(0, 0)) {
            count++;
        }
    }
    return count;
}

You can observe here that one can use regular for loops, without the need to use fold expressions and std::index_sequence for instance. Note that it requires that Plane::containsPoint becomes constexpr (which might be a no go in your case).

Demo

OTOH, it is still important to know about fold expressions and al. but it tends to make the code less readable if you’re not used to it.


If you want to keep an approach with fold expression, you might define an intermediate lambda:

auto fct = [&count] (auto w) {
    int i = w / N / P;
    int j = (w- i * N * P) / P;
    int k = (w- i * N * P - j * P);
    Plane pl = Plane {i, j, k};
    if (pl.containsPoint(0, 0))
        count++;
};

which makes computeGeneratorCount easier to write:

template <unsigned int M, unsigned int N, unsigned int P, typename T, T... ints>
constexpr int computeGeneratorCount(std::integer_sequence<T, ints...>) {
    int count = 0;
    auto fct = [&count] (auto w) {
        int i = w / N / P;
        int j = (w- i * N * P) / P;
        int k = (w- i * N * P - j * P);
        Plane pl = Plane {i, j, k};
        if (pl.containsPoint(0, 0))
            count++;
    };
    (fct(ints), ...);
    return count;
}

Demo

like image 87
abcdefg Avatar answered Sep 16 '26 19:09

abcdefg