1

I'm working on optimization of some settings code. This is a large array of predefined values groupped in three nested structures. It is defined as

struct PerId
{
    const Id m_Id;
    const uint32_t m_Flags;
};

struct PerSeverity
{
    const Severity m_Severity;
    const std::vector<PerId> m_PerId;
};

struct PerTask
{
    const Task m_Task;
    const std::vector<PerSeverity> m_PerSeverity;
};
static const std::array rawSettingsPerTask
{
    PerTask{
        eTASK1,
        {{Severity::Critical, {{Violated, 0x22}, {Expired, 0x33}}},
         {Severity::Error, {{CantBeExecuted, 0x44}}}},
    },
    PerTask{
            eTASK2,{....}
    },
};

And I want to make this settings definition compile time. I made constexpr constructors to struct and moved from std::vector to std::array and now I have compilation issues, because of different template parameters:

template<std::size_t N>
struct PerSeverity
{
    constexpr PerSeverity(Severity severity, const std::array<PerId, N>& perId)
        : m_Severity(severity)
        , m_PerId(perId)
    {}

    const Severity m_Severity;
    const std::array<PerId, N> m_PerId;
};

template<std::size_t N, size_t M>
struct PerTask
{
    constexpr PerTask(enTaskID component, const std::array<PerSeverity<M>, N>& perSeverity)
        : m_Component(component)
        , m_PerSeverity(perSeverity)
    {}

    const enTaskID m_Component;
    const std::array<PerSeverity<M>, N> m_PerSeverity;
};
constexpr std::array rawSettingsPerComponent
{
    PerComponent<1,2>{
        eTASK1, { PerSeverity<2>{Critical, { PerId{Violated, 0x22},
                                             PerId{Expired, 0x33}}}}
    },
    PerComponent<2,2>{
        eTASK2 , { PerSeverity<2>{ Critical, { PerId{Violated, 0x11},
                                               PerId{Expired, 0x22}}},
                   PerSeverity<1>{ Informational, { PerId{Violated, 0x44}}}}
    }
}

So is it possible at all? May be I need some trick, but I can't find some thing similar.

Full example here

6
  • 1
    Kindly provide a minimal reproducible example Commented May 22, 2024 at 10:16
  • @user12002570 Attached Commented May 22, 2024 at 10:37
  • You can't put a PerSeverity<1> in a PerComponent<2,2>, nor can you mix PerComponent<1,2> and PerComponent<2,2> in a std::array Commented May 22, 2024 at 10:38
  • 1
    You might be able to use tuples. Or even store initializer lists directly. Commented May 22, 2024 at 11:00
  • @Wutz Tuples will work (there's already an answer using them), but a heterogeneous {initializer-list} exists only in syntax and doesn't have an actual type. Commented May 22, 2024 at 11:12

3 Answers 3

1

You can't put a PerSeverity<1> in a PerTask<2,2>, nor can you mix PerTask<1,2> and PerTask<2,2> in a std::array.

Instead of std::array, you could use std::tuple, but that would make it harder on consumers of rawSettingsPerComponent.

template<std::size_t N>
struct PerSeverity
{
    constexpr PerSeverity(Severity severity, const std::array<PerId, N>& perId)
        : m_Severity(severity)
        , m_PerId(perId)
    {}

    const Severity m_Severity;
    const std::array<PerId, N> m_PerId;
};

template<typename... Severities>
struct PerTask
{
    constexpr PerTask(enTaskID component, const std::tuple<Severities...>& perSeverity)
        : m_Component(component)
        , m_PerSeverity(perSeverity)
    {}

    const enTaskID m_Component;
    const std::tuple<Severities...> m_PerSeverity;
};

constexpr std::tuple rawSettingsPerComponent
{
    PerTask{
        eTASK1, std::tuple{ PerSeverity<2>{Critical, { PerId{Violated, 0x22},
                                                       PerId{Expired, 0x33}}}}
    },
    PerTask{
        eTASK2 , std::tuple{ PerSeverity<2>{ Critical, { PerId{Violated, 0x11},
                                                         PerId{Expired, 0x22}}},
                             PerSeverity<1>{ Informational, { PerId{Violated, 0x44}}}}
    }
};
Sign up to request clarification or add additional context in comments.

2 Comments

Correct me if I am wrong. But isn't std::tuple constexpr since C++20 only? The OP wants a solution for C++17. So I guess they would need to stick with std::variant, right?
@UniversE no, std::tuple::tuple( const Types&... args ); and the rvalue equivalent are constexpr since C++14
0

I've decided to flesh out my idea to use initializer_list for compile-time storage of settings. Here it is on godbolt, here are the most relevant parts:


struct PerId
{
    const Id m_Id;
    const uint32_t m_Flags;
};

struct PerSeverity
{
    const Severity m_Severity;
    const std::initializer_list<PerId> m_PerId;
};

struct PerTask
{
    const Task m_Task;
    const std::initializer_list<PerSeverity> m_PerSeverity;
};
static constinit std::initializer_list<PerTask> rawSettingsPerTask
{
    PerTask{
        1,
        {{Severity::Critical, {{Violated, 0x22}, {Expired, 0x33}}},
         {Severity::Error, {{CantBeExecuted, 0x44}}}},
    },
    // PerTask{
    //         2,{....}
    // },
};

Apparently, initializer_list has been constexpr since C++14, so this should hopefully be usable for you.

Comments

0

No, it is not (kind of). For an array, you need both fixed size (=number of elements) for the array and a fixed size for the elements.

This (and some more properties) are enforced by the type of the elements. Theoretically, it is possible to store elements of different type but same size in the same array. To do that in C++, it needs some more code.

You could try, for example, to use a std::variant as the element type. It guarantees the same size (using the maximum needed size of all types the variant supports - possibly wasting a lot of memory) and the same type for all elements.

Personal note, if you allow: I strongly recommend to evaluate the benefits of all that, before implementing it, since accessing such array would always require to determine the exact type of the stored variant before you can use the value. It looks like you are over-engineering the solution.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.