Finns det något bättre sätt att kunna konvertera enums till string i C++?

Permalänk

Finns det något bättre sätt att kunna konvertera enums till string i C++?

Jag har alltid haft behov utav att kunna konvertera enums till strängar i både C och C++. I C så har jag fått göra ett sådant koncept. Notera att koden nedan är C++ kod, men det enda som skiljer är att jag har använt std::vector och std::string istället för vanlig hedlig C-string så som char-array och länkad lista. Men resultatet skulle ändå bli det samma.

Hur som helst, detta är mitt förslag på hur man kan konvertera enums till sträng. Då är frågan: Finns det något bättre sätt i C++?

typedef enum { USB_PROTOCOL_MODBUS, USB_PROTOCOL_CDC, USB_PROTOCOL_MAX_INDEX }USB_PROTOCOL; std::string Tools_Hardware_USB_getProtocolString(const USB_PROTOCOL protocol) { switch (protocol) { case USB_PROTOCOL_MODBUS: return "Modbus"; case USB_PROTOCOL_CDC: return "CDC"; default: return "NO PROTOCOL FOUND"; } } USB_PROTOCOL Tools_Hardware_USB_searchProtocol(const std::vector<std::string> &protocols, const std::string &protocol) { for (size_t i = 0; i < protocols.size(); i++) { if (protocols.at(i).compare(protocol) == 0) { switch (i) { case USB_PROTOCOL_MODBUS: return USB_PROTOCOL_MODBUS; case USB_PROTOCOL_CDC: return USB_PROTOCOL_CDC; default: return USB_PROTOCOL_MODBUS; } } } } std::vector<std::string> Tools_Hardware_USB_getAllProtocolStrings() { std::vector<std::string> protocols; for (int i = 0; i < USB_PROTOCOL_MAX_INDEX; i++) { std::string protocol = Tools_Hardware_USB_getProtocolString((USB_PROTOCOL)i); protocols.push_back(protocol); } return protocols; }

Permalänk

Kanske en map<string, USB_PROTOCOL>?

Permalänk
Hedersmedlem

Jag har inte testat, men detta ser ju spännande ut: https://github.com/Neargye/magic_enum
(Man bör kanske läsa begränsningarna också, dock)

Permalänk
99:e percentilen

Tänker att det inte borde behövas något mer avancerat än en vanlig hederlig funktion vars implementation består av en switch-sats. Det verkar du också ha tänkt, men du lär väl göra dig av med default och kompilera med -Werror, så att kompilatorn kan rapportera fel vid icke-totala implementationer, såsom din Tools_Hardware_USB_getProtocolString, som inte hanterar USB_PROTOCOL_MAX_INDEX.

Sedan bör man, enligt tidigare länkad artikel, tydligen även lägga till en return- eller throw-sats efter switch-satsen för att undvika odefinierat beteende i vissa scenarier. Personligen hade jag valt throw.

Visa signatur

Skrivet med hjälp av Better SweClockers

Permalänk
Datavetare

Eftersom du definierar USB_PROTOCOL_MAX_INDEX, varför inte bara gör något likt detta

#include <array> #include <algorithm> #include <string> namespace Tools_Hardware_USB { enum USB_PROTOCOL { USB_PROTOCOL_MODBUS, USB_PROTOCOL_CDC, USB_PROTOCOL_MAX_INDEX }; const std::array<std::string, USB_PROTOCOL_MAX_INDEX> &getAllProtocolStrings() { static const std::array<std::string, USB_PROTOCOL_MAX_INDEX> usb_protocol_names{ "Modbus", "CDC", }; return usb_protocol_names; } const std::string &getProtocolString(const USB_PROTOCOL protocol) { auto allProtos = getAllProtocolStrings(); if (protocol < 0 || protocol >= allProtos.size()) return "NO PROTOCOL FOUND"; return allProtos[protocol]; } USB_PROTOCOL searchProtocol(const std::string &protocol_name) { auto allProtos = getAllProtocolStrings(); auto first = allProtos.begin(); auto last = allProtos.end(); auto it = std::find(first, last, protocol_name); return (it == last) ? USB_PROTOCOL_MODBUS : (USB_PROTOCOL)(it - first); } } // just for test #include <iostream> int main() { std::cout << Tools_Hardware_USB::searchProtocol("CDC") << std::endl; std::cout << Tools_Hardware_USB::getProtocolString(Tools_Hardware_USB::USB_PROTOCOL_MODBUS) << std::endl; }

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk

Det blev lite grötigt med att använda enums när man behöver dom i strängar.

Så jag gjorde om koden och använde bara strängar helt enkelt.

Och istället använde jag mallar.

template <typename T, std::size_t N> int Tools_Software_Algorithms_findIndexOf(const T(&arr)[N], const T& value) { for (std::size_t i = 0; i < N; i++) { if (arr[i] == value) { return i; } } return -1; // Not found } template <typename T, std::size_t N> constexpr std::size_t Tools_Software_Algorithms_getArraySize(const T(&)[N]) { return N; }

Jag hoppas att detta ska fungera bättre.

Permalänk
Medlem
Skrivet av heretic16:

Det blev lite grötigt med att använda enums när man behöver dom i strängar.

Så jag gjorde om koden och använde bara strängar helt enkelt.

Och istället använde jag mallar.

template <typename T, std::size_t N> int Tools_Software_Algorithms_findIndexOf(const T(&arr)[N], const T& value) { for (std::size_t i = 0; i < N; i++) { if (arr[i] == value) { return i; } } return -1; // Not found } template <typename T, std::size_t N> constexpr std::size_t Tools_Software_Algorithms_getArraySize(const T(&)[N]) { return N; }

Jag hoppas att detta ska fungera bättre.

Jag kan inte C++ så bra men har sett dig skriva i andra trådar att prestanda är väldigt viktigt för dig. Den här lösningen verkar ha en annan filosofi om vi säger så, åtminstone jämfört med lösningarna ovan?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Det blev lite grötigt med att använda enums när man behöver dom i strängar.

Ett alternativ är väl att skapa någon typ av klasser (där namn är en egenskap som ingår)? Då kan man i alla fall definiera allt på samma ställe.