Глядя на заголовок, хорошая точка настройки:
namespace boost { namespace property_tree
{
template <typename Ch, typename Traits, typename E, typename Enabler = void>
struct customize_stream
{
static void insert(std::basic_ostream<Ch, Traits>& s, const E& e) {
s << e;
}
static void extract(std::basic_istream<Ch, Traits>& s, E& e) {
s >> e;
if(!s.eof()) {
s >> std::ws;
}
}
};
имеет поле Enabler.
namespace boost { namespace property_tree {
template <typename Ch, typename Traits, typename E>
struct customize_stream<Ch, Traits, E,
std::enable_if_t< /* some test */ >
>
{
static void insert(std::basic_ostream<Ch, Traits>& s, const E& e) {
// your code
}
static void extract(std::basic_istream<Ch, Traits>& s, E& e) {
// your code
}
};
, где вы можете поместить любой код в // your code
и любой тест в /* some test */
.
Оставшаяся часть состоит в том, чтобы (а) связать bob::a
с "a"
и (б) связать это с вышеприведенным.
Мне нравится делать эти ассоциации в пространстве имен bob
, а затем находить их через ADL.
Создать template<class T> struct tag_t {}
. Если вы передадите tag_t<foo>
функции, ADL найдет функции как в пространстве имен tag_t
, так и в пространстве имен foo
.
Создать функцию, которая получает отображение от значения enum на строку (и обратно). Предположим, что ваше отображение:
std::vector< std::pair< E, std::string > >
и вы просто делаете линейный поиск. Тогда:
namespace string_mapping {
template<class Enum>
using mapping = std::vector<std::pair< Enum, std::string > >;
}
namespace some_ns {
enum bob { a, b, c };
string_mapping::mapping<bob> const& get_string_mapping( tag_t<bob> ) {
static string_mapping::mapping<bob> retval = {
{bob::a, "a"},
{bob::b, "b"},
{bob::c, "c"},
};
return retval;
}
}
мы можем найти это отображение там, где у нас есть тип T=bob
, выполнив get_string_mapping( tag_t<T>{} )
.
Используйте что-то вроде can_apply
, чтобы определить, можно ли найти get_string_mapping( tag_t<T>{} )
, используйте его, чтобы разрешить вашему пользовательскому customize_stream
использовать get_string_mapping
для загрузки / сохранения данных в / из потоков.
Теперь все, что нам нужно сделать, это уменьшить боль от письма get_string_mapping
.
#define MAP_ENUM_TO_STRING( ENUM ) \
string_mapping::mapping<ENUM> const& get_string_mapping( tag_t<ENUM> ) { \
static string_mapping::mapping<ENUM> retval =
#define END_ENUM_TO_STRING ; return retval; }
использование:
MAP_ENUM_TO_STRING( bob )
{
{bob::a, "a"},
{bob::b, "b"},
{bob::c, "c"},
}
END_ENUM_TO_STRING
в пределах пространства имен bob
.
Если вы хотите что-то более изощренное (ooo, отсортированные списки или неупорядоченные карты), это можно легко сделать в get_string_mapping
или даже с помощью get_efficient_string_mapping
, который вызывает get_string_mapping
и выполняет однократную повторную обработку квартиры данные.
Большим преимуществом этого является то, что нам не нужно делать это в глобальном пространстве имен; мы можем поместить это естественно прямо в перечисление или в пространство имен перечисления.