Home > Mobile >  How implement a lookup utility class with an array member variable?
How implement a lookup utility class with an array member variable?

Time:04-15

Live On Coliru

I need to implement a utility class for the purpose of lookup. The value of the internal array never changes after the initialization. My initial plan was to implement this class with the help of constexpr so that the expensive initialization can be done in compilation time. However, I am not able to come up with a good solution. So far, I can only figure out the following two methods. Both methods have drawbacks.

Method One: The implementation looks complicate for such a simple task.

Method Two:

First, I assume the initialization is done in compilation time. Is this correct?

Second, the TwoClass::m_array really should be static instead of a member variable.

Is there a better way to implement this with c 20?

Thank you

#include <iostream>
#include <array>

using namespace std;

//== Method One
class OneClass
{
public:
    uint32_t get(size_t index)
    {
        return m_array[index % 0xFF];
    }

    struct init_static_array
    {
        init_static_array()
        {
            std::cout << "call init_static_array\n";
            for (int i = 0; i < N; i  ) {
                m_array[i] = i * i   10;
            }
        }
    };
    
private:
    static init_static_array m_init_static_array;
    enum {N = 255};
    static int m_array[N]; // this is a lookup table and NEVER will be changed!
};

int OneClass::m_array[] = {0};
OneClass::init_static_array OneClass::m_init_static_array{};

//== Method Two
class TwoClass
{
public:
    constexpr TwoClass()
    {
        std::cout << "call TwoClass::TwoClass()\n";
        for (int i = 0; i < N; i  ) {
            m_array[i] = i * i   10;
        }
    }
    
    int get(size_t index) const
    {
        return m_array[index % 0xFF];
    }
    
private:
    enum {N = 255};
    int m_array[N] {0}; // this is a lookup table and NEVER will be changed!
};

int main()
{
    OneClass oneclass;
    cout << "1 => " << oneclass.get(1) << std::endl;
    cout << "256 => " << oneclass.get(256) << std::endl;
    
    cout << "==================\n";
    
    TwoClass twoclass;
    cout << "1 => " << twoclass.get(1) << std::endl;
    cout << "256 => " << twoclass.get(256) << std::endl;

    return 0;
}

Output:

call init_static_array
1 => 11
256 => 11
==================
call TwoClass::TwoClass()
1 => 11
256 => 11

CodePudding user response:

If it's C 20, don't you just want this:

namespace {
constexpr std::size_t N{255u};
consteval std::array<int, N> initArr()
{
    std::array<int, N> arr{};
    for (int i = 0; i < N; i  ) {
        arr[i] = i * i   10;
    }
    return arr;
}
}
class C
{
private:
    constexpr static std::array<int, N> arr{initArr()};
public:
    constexpr C() = default;
    int get(std::size_t n) const {return arr[n%5];}
};

CodePudding user response:

Neither of your methods initialized the array at compile-time.

In the first method, the array is initialized in construction of static data member m_init_static_array, e.g. before main is called.

In the second method, constexpr in function declarations, including constructors, indicates that you want them being able to be called at compile-time, e.g. in evaluation of constant expressions. It doesn't mean all invocations are evaluated at compile-time. To call constexpr functions as compile-time, you have to call them in constant expression.

One solution is to initialize the static constexpr data member internal_array of type std::array by a lambda:

#include <array>

class Demo {
public:
    int get(int index) const {
      return internal_array[index % N];
    }

private:
    static inline constexpr int N = 255;

    static inline constexpr std::array<int, N> internal_array = []() {
        // Cannot call non-constexpr functions at compile-time
        // std::cout << "std::cout << "call init_static_array\n";

        std::array<int, N> arr;
        for (int i = 0; i < N;   i)
            arr[i] = i * i   10;
        return arr;
    }();
};

int main() {
  Demo demo;
  return demo.get(10);
}
  • Related