Попытка создать систему привязки пользовательского интерфейса. Элементы пользовательского интерфейса могут указывать имя поля и ожидать строку - PullRequest
0 голосов
/ 23 апреля 2020

Я просто собираюсь сбросить текущий код.

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 (), это привело бы к мягкой ошибке времени выполнения во время связывания.

...