Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to convert C-style compile-time arrays to std::array

Tags:

c++

arrays

c++17

In our sources we have often something like this:

static const int g_numbers[]{ 1, 2, 3, 4, 5};
static const struct
{
    const int         m_nID;
    const char* const m_pszName;
}
g_collection[]
{
    { 1, "Max" },
    { 2, "Fabian" },
    { 3, "Martin" },
    …
};

How to transform those compile-time arrays to modern C++? Using e.g. std::array?

If I understood it correctly, std::array needs a size as template argument.

Which way would you suggest to transform such code with minimum overhead (e.g. code generation) and unnecessary, redundant information?

like image 814
Martin Lemburg Avatar asked Dec 03 '22 09:12

Martin Lemburg


2 Answers

You have a choice. Either use template argument deduction, or specify the arguments yourself.

Using template argument deduction:

static constexpr std::array g_numbers{1, 2, 3, 4, 5};

struct g_collection_element
{
    int         m_nID;
    char const* m_pszName;
};

static constexpr std::array g_collection{
    g_collection_element{ 1, "Max" },
    g_collection_element{ 2, "Fabian" },
    g_collection_element{ 3, "Martin" },
};

As you can see here, I named the struct and used it after declaration. I also removed the const from the members as they are not really useful in that case.

Also, for template argument deduction to work, you must type out the type of the elements for each initializer in the array, or the compiler won't perform template argument deduction.

Specifying the arguments:

static constexpr std::array<int, 5> g_numbers{1, 2, 3, 4, 5};

struct g_collection_element
{
    int         m_nID;
    char const* m_pszName;
};

static constexpr std::array<g_collection_element, 3> g_collection{
    { 1, "Max" },
    { 2, "Fabian" },
    { 3, "Martin" },
};

You sadly can't only specify the type to let the number to be deduced.

like image 195
Guillaume Racicot Avatar answered Dec 29 '22 10:12

Guillaume Racicot


To complement the other answer with a C++20 solution (despite the C++17 cap), you can obviate some of the extra elem mentions by using std::to_array

static constexpr auto g_collection = std::to_array<elem>(
{
    { 1, "Max" },
    { 2, "Fabian" },
    { 3, "Martin" },
});

Specify elem once, and leave the size to be deduced. Since the type is provided explicitly, the brace initializer need not be typed anymore.

This may look like it's creating two objects (a temp raw array and a static std::array), but by the graces of constant evaluation, this is collapsed into one hardcoded object.

like image 27
StoryTeller - Unslander Monica Avatar answered Dec 29 '22 12:12

StoryTeller - Unslander Monica