Я просто собираюсь сбросить текущий код.
using UnitFnInt = int(Chain::Unit::*)(void) const;
using UnitFnFloat = float(Chain::Unit::*)(void) const;
using UnitFnString = std::string (Chain::Unit::*)(void) const;
std::unordered_map<std::string, std::any> bindMap;
void Init()
{
bindMap.emplace(std::make_pair("Unit.Name", std::any(&Unit::GetName)));
bindMap.emplace(std::make_pair("Unit.Level", std::any(&Unit::GetLevel)));
}
template<typename T>
std::string Execute(std::any a, T& t)
{
if (a.type() == typeid(UnitFnInt))
{
auto fn = std::any_cast<UnitFnInt>(a);
return std::to_string((t.*fn)());
}
else if (a.type() == typeid(UnitFnFloat))
{
auto fn = std::any_cast<UnitFnFloat>(a);
return std::to_string(std::any_cast<float>(a));
}
else if (a.type() == typeid(UnitFnString))
{
auto fn = std::any_cast<UnitFnString>(a);
return std::any_cast<std::string>(a);
}
else
{
return std::string("");
}
}
std::string GetField(Unit& u, const std::string& field)
{
auto it = bindMap.find(field);
if (it != bindMap.end())
{
auto f = it->second;
return Execute<Unit>(f, u);
}
return std::string("");
}
С вышесказанным вызовите GetField (u, "Unit.Name"), и он вернет имя устройства (строку). Аналогично, GetField (u, «Unit.Level») вернет уровень юнита (целое число). Обратите внимание на различные типы возвращаемых функций.
Это прекрасно работает. Проблема в том, что существует гораздо больше классов, чем просто Unit, к которому может быть привязан элемент пользовательского интерфейса, поэтому это должно работать для обобщенного c типа T. Проблемы начинаются с std :: any, чтобы указатели на функции-члены возвращали строку , int или float, так как я пытаюсь сделать это отображение, используя существующие функции класса, а не создавать новые. Я ищу предложения. Я бы поговорил о шаблонной установке, которую я пробовал, но она стала действительно сложной, и мне это не нравится.
Другая проблема - некоторые свойства должны иметь возможность принимать один параметр. Имя поля может быть привязано либо к индексируемому, либо к неиндексированному вызову функции. Второй метод GetField (), который принимает третий параметр индекса, - это все, что необходимо на уровне API. Разбить это на две части, одну для индексированных и одну для неиндексированных, допустимо. Мое оригинальное шаблонное решение (кратко упомянутое выше) собиралось обрабатывать оба, и если вы вызвали неправильный GetField (), это привело бы к мягкой ошибке времени выполнения во время связывания.