Indeksowanie tablicy enumem

0

Mam sobie tablicę o wielkości znanej podczas kompilacji, którą chciałbym indeksować poprzez znaną z góry listę słów kluczowych. Powiedzmy, coś w stylu RGBA_values[RGBA::RED] = 42;

Jak to zrobić najładniej? Kilka pomysłów:

  • std::array i przeładować operator[] dla swojego enum class — sporo babraniny.
  • std::map — wydajność nie taka…
  • std::array i „goły” enum — brak type safety mi trochę przeszkadza, ale na razie mi się ta opcja podoba najbardziej

Jak jakieś kolekcje/inne cuda z Qt6 będą przydatne, to też chętnie przyjmę. Standard to C++20.

0

Na pewno jest problem z wydajnością map?

0

Tak. Pewnie by się dało temu zapobiec, jakby wymusić, żeby to siedziało na stosie zamiast na stercie, ale nie wiem jak to osiągnąć.

3

Brakuje trochę kontekstu. Zakładając, że to ma być jeden z wielu elementów jakiejś klasy, to bym zrobił odpowiednie settery i gettery dla danego enuma. Alternatywnie, opakowałbym to w osobną klasę (czyli opcja 1, jak mniemam) - to nie powinno być aż tyle roboty.

Protip, jeśli nie znałeś: std::get na std::array wymusza sprawdzanie indeksów w czasie kompilacji

2

Hmm, a co jest nie tak ze zrobieniem enum class Color : size_t, i takim zwięzłym przeładowaniem operatora:

template <typename T, size_t N>
T& operator[](std::array<T, N>& arr, const Color& c) {
    return arr[static_cast<size_t>(c)];
}

Piszę z palca więc może się coś nie kompiluje, ale afaik powinno działać.

0
kq napisał(a):

Brakuje trochę kontekstu. Zakładając, że to ma być jeden z wielu elementów jakiejś klasy, to bym zrobił odpowiednie settery i gettery dla danego enuma. Alternatywnie, opakowałbym to w osobną klasę (czyli opcja 1, jak mniemam) - to nie powinno być aż tyle roboty.

Szerszy kontekst jest taki, że chcę mieć wielką tablicę takich tablic i na niej robić różne powolne cuda. Każda z tych pod-tablic (tzn. te małe tablice, które chcę indeksować enumem) będzie właściwie tylko kontenerem na dane, cała logika będzie siedzieć gdzie indzie. Nie będę pewnie zbyt mocno szedł w obiektowość, bo nie widzę tutaj zalet.

Ogólnie w przyszłości będę też myśleć nad tym, jak to zwektoryzować, więc im prostsze struktury danych, tym mniejsza szansa, że wyłysieję przy tym — co prawda jeszcze nie jestem na tym etapie, ale mimo wszystko wolę się potem nie obudzić z ręką w nocniku, gdy będę musiał przepisać cały program tak naprawdę bo kompilator nie ogarnia, że może.

0

@Althorion: nie o taki kontekst chodzi. Ty się cały czas skupiasz na tym jakbyś chciał coś zrobić, a kq i ja chcielibyśmy wiedzieć co chciałbyś zrobić.
Czyli mówiąc prościej co ten kod ma robić? Jaką logikę biznesową ma dostarczyć.

3

Możesz skorzystać z biblioteki std::pmr aby std::unordered_map był tworzony na stosie, wykorzystując do tego std::array jako bufor. Minus jest taki że musisz manualnie kontrolować wielkość pamięci bufora.

#include <iostream>
#include <memory_resource>
#include <unordered_map>

using namespace std;

enum class RGB { RED , GREEN , BLUE };

int main()
{
    // buffer located on stack
    array< byte , 200 > buf;

    pmr::monotonic_buffer_resource pool{ buf.data() , buf.size() , pmr::null_memory_resource() };
    pmr::unordered_map<RGB,int> color{&pool};

    color[RGB::RED] = 255;
    color[RGB::GREEN] = 0;
    color[RGB::BLUE] = 255;

    cout << color[RGB::RED] << ' ' << color[RGB::GREEN] << ' ' << color[RGB::BLUE] << endl;
    cout << &color[RGB::RED] << ' ' << &color[RGB::GREEN] << ' ' << &color[RGB::BLUE]<< endl;
    cout << &*begin(buf) << " - " << &*rbegin(buf) << endl;
}

https://godbolt.org/z/4eb73vq4c

1

Albo możesz sprawdzić abseilową flat_hash_map, która ma być zoptymalizowaną std::unordered_map https://github.com/abseil/abseil-cpp/blob/master/absl/container/flat_hash_map.h

0

@Althorion:
Może coś takiego?

#include <array>
#include <iostream>
#include <string_view>

int main()
{
	constexpr size_t N = 2;
	using pair = std::pair<int, std::string_view>;
	constexpr std::array<pair, N> map = { pair(1, "jeden"), pair(2, "dwa") };

	for (const auto& [key, value] : map)
	{
		std::cout << key << " " << value << '\n';
	}
}
0

Nie rozumiem jaki problem jest z indeksacją tablicy za pomocą enuma?

#include <iostream>
using namespace std;

enum Xxx { aaa,bbb,ccc };
Xxx operator++(Xxx &x) { return x=(Xxx)(1+(int)x); } // jak nie ma przerw to zadziała poprawnie

typedef void Run();

int main()
{
	Run *run[]=
	{
		/*aaa*/ [](){ cout<<"(aaa)"<<endl; },
		/*bbb*/ [](){ cout<<"(bbb)"<<endl; },
		/*ccc*/ [](){ cout<<"(ccc)"<<endl; },
	};
	string str[]=
	{
		/*aaa*/ "(aaa)",
		/*bbb*/ "(bbb)",
		/*ccc*/ "(ccc)",
	};
	
	for(Xxx i=aaa;i<=ccc;++i) run[i]();
	cout<<endl;
	for(Xxx i=aaa;i<=ccc;++i) cout<<str[i]<<endl;
	cout<<endl;
	
    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1