В C возможно ли сделать переменную одновременно легкой для доступа и легкой для повторения?

#c #variables #iteration

#c #переменные #итерация

Вопрос:

Я рефакторингую систему «profiles» с целью уменьшения количества повторяющегося кода, необходимого для сохранения, загрузки и доступа к настройкам. Однако я обнаружил, что я просто перетасовываю повторяющийся код (уменьшение его в одном месте увеличивает его в другом). Я чувствую, что мне чего-то не хватает.

Обратите внимание, в этой схеме существует концепция профиля «по умолчанию», который выборочно маскируется «загруженным» профилем. Пользователь может настроить все параметры в профиле по умолчанию, а затем просто изменить конкретные настройки для других профилей. Например, пользователь может захотеть использовать один и тот же номер порта для всех профилей (определенный в профиле по умолчанию), но указать другой IP-адрес для подключения к разным компьютерам (определенный в загруженном профиле). Эта функциональность на самом деле еще не реализована, это одна из причин, по которой я занимаюсь рефакторингом.

Каждый параметр должен быть связан со следующей информацией:

  1. Строка, используемая для ее идентификации в XML.
  2. Int, bool или string, который определяет фактическое значение настройки.
  3. Логическое значение, которое указывает, использовать ли указанное выше значение или значение по умолчанию.

Изначально я определил все это как переменные-члены структуры. Это очень просто использовать для доступа к настройкам. Я могу просто передать структуру профиля любой функции, которой требуются настройки, а затем получить доступ к определенному параметру с помощью 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. Я отвечал на свой собственный вопрос.