#c #variables #iteration
#c #переменные #итерация
Вопрос:
Я рефакторингую систему «profiles» с целью уменьшения количества повторяющегося кода, необходимого для сохранения, загрузки и доступа к настройкам. Однако я обнаружил, что я просто перетасовываю повторяющийся код (уменьшение его в одном месте увеличивает его в другом). Я чувствую, что мне чего-то не хватает.
Обратите внимание, в этой схеме существует концепция профиля «по умолчанию», который выборочно маскируется «загруженным» профилем. Пользователь может настроить все параметры в профиле по умолчанию, а затем просто изменить конкретные настройки для других профилей. Например, пользователь может захотеть использовать один и тот же номер порта для всех профилей (определенный в профиле по умолчанию), но указать другой IP-адрес для подключения к разным компьютерам (определенный в загруженном профиле). Эта функциональность на самом деле еще не реализована, это одна из причин, по которой я занимаюсь рефакторингом.
Каждый параметр должен быть связан со следующей информацией:
- Строка, используемая для ее идентификации в XML.
- Int, bool или string, который определяет фактическое значение настройки.
- Логическое значение, которое указывает, использовать ли указанное выше значение или значение по умолчанию.
Изначально я определил все это как переменные-члены структуры. Это очень просто использовать для доступа к настройкам. Я могу просто передать структуру профиля любой функции, которой требуются настройки, а затем получить доступ к определенному параметру с помощью profile.thingy
.
К сожалению, сохранение и загрузка настроек в этой схеме требует добавления отдельного кода сохранения / загрузки для каждой настройки. Аналогично, для создания «объединенного» профиля настроек, объединяющего профили по умолчанию и текущие, потребуется вручную кодировать слияние для каждого параметра. Мне также нужно было добавить отдельные переменные «useDefault» и «xmlName» для каждого параметра. Все это было немного глупо.
Для начала я реализовал шаблон класса SerfSetting
, который содержит 3 части данных, упомянутых ранее.
template <class T>
class SerfSetting {
public:
T value;
string xmlName;
bool useDefault = false;
Это немного более раздражает при доступе, поскольку теперь мне нужно писать profile.setting.value
везде, но это не так уж плохо. Я также перегружен =
и ==
для работы с value
вместо самого объекта, поэтому иногда это прозрачно.
Настоящая проблема заключается в том, что я пытаюсь превратить это во что-то итеративное, чтобы избавить себя от необходимости повторять S / L / M (сохранение / загрузка / слияние) код для каждой новой настройки.
То, что я сейчас рассматриваю, — это использование std::any
или отдельного std::vector
или std::map
для каждого типа данных. Для S / L / M это было бы идеально, очень просто для итерации. Однако затем доступ к параметру становится profile.listOfSettings[SETTING_INDEX_CONSTANT].value
(или аналогичным), что довольно абсурдно для обычной задачи и добавляет потенциал для ошибок во время выполнения, которые могут быть трудно обнаружить (поскольку мне нужно вручную поддерживать константы индекса настроек и вручную обеспечивать доступ к правильной настройке).
В идеале я мог бы просто перебирать переменные-члены структуры profile, но в Интернете совершенно ясно, что «C не поддерживает отражение», и альтернативы, которые я видел, такие же надуманные и уродливые, как то, что я описал выше.
Есть ли разумное решение этой проблемы, или я смирился с тем, что где-то есть что-то уродливое?
Спасибо!
Комментарии:
1. Вы смотрели на дерево свойств Boost?
2. «То, что я рассматриваю прямо сейчас, — это использование std::any или отдельного std::vector или std::map» Почему бы просто не объединить их, чтобы настроить дерево значений конфигурации ?
std::optional
также может пригодиться.
Ответ №1:
Я ценю ваши комментарии и рад, что теперь знаю об этих инструментах (хотя я не уверен, что std::optional
применимо в этом случае, поскольку ожидается, что все значения будут ненулевыми при обращении к ним).
Как это часто бывает, найти время, чтобы четко сформулировать проблему словами, помогло мне решить ее. Я понял, что после публикации я делал ложное предположение, что мне нужно получить доступ к настройкам и выполнить итерацию с использованием одного и того же объекта.
Я считаю, что простое решение заключается в следующем:
struct SerfProfile {
vector<SerfSetting<string>*> stringPtrList;
SerfSetting<string> IPaddress = SerfSetting<string>();
SerfProfile() {
stringPtrList.push_back(amp;IPaddress);
}
};
Я могу получить доступ к настройке с помощью IPaddress.value
и повторить настройки с помощью stringPtrList
. Это также упрощает настройку профиля, отличного от S / L / M, если мне когда-нибудь понадобится это сделать по какой-либо причине.
Я ценю, что вы нашли время, чтобы изучить эту проблему.
Комментарии:
1. Я отвечал на свой собственный вопрос.