Question Details

No question body available.

Tags

c++

Answers (3)

Accepted Answer Available
Accepted Answer
July 17, 2026 Score: 1 Rep: 46,305 Quality: High Completeness: 80%

You can use the builder pattern to get something that looks like this:

constexpr auto ServicesNames = ArrayBuilder()
    .e("https://bitbucket.org/.")
    .e("https://github.com/.")
    .e("https://gitlab.com/.*")
    .build();

Implementation (https://godbolt.org/z/Y9YYn8TW4):

#include 
#include 
#include 
#include 

template struct Part { std::tuple args; static constexpr std::sizet index = I; };

template struct ArrayBuilder { std::tuple parts;

template constexpr auto e(Args&&... args) && { static constexpr std::size
t index = staticcast(I); staticassert(((index != Parts::index) && ...), "index appears multiple times!"); return std::apply([&](const auto&... parts) { using newparttype = Part; return ArrayBuilder{ std::tuple( parts..., newparttype{ std::tuple(std::forward(args)...) } ) }; }, parts); }

private: static constexpr std::sizet maxindex = std::max({ 0zu, Parts::index... });

template constexpr T initializeforindex() { if constexpr (J == sizeof...(Parts)) { return T(); } else if constexpr (std::tupleelementt::index == I) { return std::apply([](Args&&... args) { return T(std::forward(args)...); }, std::get(parts).args); } else { return initializeforindex(); } }

public: constexpr auto build() && { return [&](std::indexsequence) { return std::array{ { initializeforindex()... } }; }(std::makeindex_sequence{}); } };
July 17, 2026 Score: 7 Rep: 61,382 Quality: High Completeness: 80%

You can reflect the enumerator to create an aggregate type with members having the same names as enumerators. The resulting user code is then:

constexpr auto serviceNames = ServiceNames{
    .github = "https://github.com/.",
    .gitlab = "https://gitlab.com/.",
    .bitbucket = "https://bitbucket.org/.*",
};

which achieves the readability you're looking for. This does mean the members have to appear in the same order as the original enumerators, but that's probably not a usability issue. Members don't have to all be named, they'll just have default values.

The implementation of ServiceNames is actually simple (once you get over some of the new syntax and meta functions):

struct ServiceNames;

consteval { // a range of all the final members std::vector members;

// for each enumerator in 'Service' template for (constexpr auto enumerator : definestaticarray(std::meta::enumeratorsof(^^Service))) { // create a member with the same name as the enumerator, and type std::stringview members.pushback( std::meta::datamemberspec( ^^std::stringview, { .name = std::meta::identifierof(enumerator)})); }

// actually create 'ServiceNames' (which so far is incomplete) with all the members. std::meta::defineaggregate(^^ServiceNames, members); }

The implementation is inspired by (and in fact, pretty much directly copied from) this recent C++ Weekly talk, which I highly recommend. (It also shows how you could write this inside a function, so if you have multiple enums like Service, you only need to write this class-generator once).

Demo

July 17, 2026 Score: 2 Rep: 41,286 Quality: Medium Completeness: 80%

The main issue is to find last possible enum value.
In C++26 it should be simple.

In earlier version of the C++ standard you can add terminating spacial value in enumeration to detect how big resulting array should be:

template 
consteval auto toarraydesignated(const std::pair (&a)[N])
{
    std::array result { };

for (auto& [k, v] : a) { result[std::tounderlying(k)] = v; }

return result; }

enum Services : sizet { github = 0, gitlab = 1, bitbucket = 4, google = 7,

sizeinfo, };

constexpr auto ServicesNames = toarraydesignated({ { Services::bitbucket, "https://bitbucket.org/.*" }, { Services::github, "https://github.com/.*" }, { Services::gitlab, "https://gitlab.com/.*" }, });

Then it works.

magicenum library is quite handy and can help determine size of result array:

template 
consteval auto toarraydesignated(const std::pair (&a)[N])
{
    constexpr auto values = magicenum::enumvalues();
    constexpr auto maxvalue = std::tounderlying(values.back());

std::array result { };

for (auto& [k, v] : a) { result[std::tounderlying(k)] = v; }

return result; }

enum Services : sizet { github = 0, gitlab = 1, bitbucket = 4, google = 7, };

constexpr auto ServicesNames = toarraydesignated({ { Services::bitbucket, "https://bitbucket.org/." }, { Services::github, "https://github.com/." }, { Services::gitlab, "https://gitlab.com/.*" }, });

Seems to work well.
Here is example with more data.