Last active
November 15, 2021 09:40
-
-
Save shawnfeng0/722d5307341d4b669f02cf08a4bf51c0 to your computer and use it in GitHub Desktop.
Define an enum that can be converted to a string
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by shawnfeng([email protected]) on 2021/11/1. | |
// | |
#pragma once | |
#include <map> | |
#include <string> | |
#include <vector> | |
// reference: | |
// https://stackoverflow.com/questions/207976/how-to-easily-map-c-enums-to-strings | |
// https://stackoverflow.com/questions/201593/is-there-a-simple-way-to-convert-c-enum-to-string#201792 | |
namespace enum_string { | |
template <typename T> | |
static inline void split_string_for_each(const std::string &str, | |
const std::string &delimiter, | |
const T &foreach_function, | |
ssize_t max_number = -1) { | |
ssize_t num = 0; | |
std::string::size_type start; | |
std::string::size_type end = -1; | |
while (true) { | |
start = str.find_first_not_of(delimiter, end + 1); | |
if (start == std::string::npos) break; // over | |
end = str.find_first_of(delimiter, start + 1); | |
if (end == std::string::npos) { | |
foreach_function(num, str.substr(start)); | |
break; | |
} | |
foreach_function(num, str.substr(start, end - start)); | |
++num; | |
if (max_number > 0 && num == max_number) break; | |
} | |
} | |
/** | |
* Strip function, delete the specified characters on both sides of the string. | |
*/ | |
inline std::string &strip(std::string &s, | |
const std::string &characters = " \t\r\n") { | |
s.erase(0, s.find_first_not_of(characters)); | |
return s.erase(s.find_last_not_of(characters) + 1); | |
} | |
template <typename UnderlyingType> | |
static inline std::map<UnderlyingType, std::string> ParserEnumDefine( | |
const std::string &name, const std::string &define_str) { | |
UnderlyingType cur_num = 0; | |
std::string cur_item_str; | |
std::map<UnderlyingType, std::string> result_map; | |
split_string_for_each(define_str, ",", [&](int num, const std::string &str) { | |
split_string_for_each( | |
str, "=", | |
[&](int num, const std::string &str) { | |
if (num == 0) cur_item_str = str; | |
if (num == 1) cur_num = std::stoi(str); | |
}, | |
2); | |
result_map.emplace(cur_num, name + "::" + strip(cur_item_str)); | |
cur_num++; | |
}); | |
return result_map; | |
} | |
} // namespace enum_string | |
/** | |
* Example: | |
* @code | |
#include <iostream> | |
#include "enum_with_string.h" | |
ENUM_WITH_STRING(Animal, dog, cat, monkey = 50, fish, human = 100, duck) | |
int main() { | |
std::cout << to_string(Animal::dog) << std::endl; | |
std::cout << to_string(Animal::cat) << std::endl; | |
std::cout << to_string(Animal::monkey) << std::endl; | |
std::cout << to_string(Animal::fish) << std::endl; | |
std::cout << to_string(Animal::human) << std::endl; | |
std::cout << to_string(Animal::duck) << std::endl; | |
} | |
* @endcode | |
*/ | |
#define ENUM_WITH_STRING(Name, ...) \ | |
enum class Name { __VA_ARGS__, __COUNT }; \ | |
static inline const std::string &to_string(Name value) { \ | |
using underlying_type = std::underlying_type<Name>::type; \ | |
static const auto map = \ | |
enum_string::ParserEnumDefine<underlying_type>(#Name, #__VA_ARGS__); \ | |
static const std::string cannot_converted = \ | |
"Cannot be converted to string"; \ | |
underlying_type under_value = static_cast<underlying_type>(value); \ | |
if (map.count(under_value)) \ | |
return map.at(under_value); \ | |
else \ | |
return cannot_converted; \ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment