Шаблонные классы C ++ / Qt - PullRequest
       3

Шаблонные классы C ++ / Qt

1 голос
/ 15 февраля 2012

У меня есть приложение, которое будет получать сообщения из другого приложения.Эти сообщения будут представлять собой строки в формате XML, и они будут содержать тег <messageType>.Тип сообщения будет определять это сообщение как тип внутреннего сообщения.Следующий код показывает мои внутренние структуры сообщений.

namespace
Application1{

enum ApplicationAttributes{
    ApplicationName = 1000,
    Start,
    Stop,
    Pause,
    Save,
    Discard,
    SelectRunway,
    DoAlignment,
    RedoAlignment,
    AlignmentOK,
    DoCalibrationStage1,
    SetCalibrationStage1,
    SetCalibrationStage2,
    SetCalibrationStage3,
    CancelCalibration,
    CalibrationOK
};


struct Alignment{
    int x;
    int y;
    int error;
};

struct Calibration{
    int x;
    int y;
    int error;
};

}

выравнивание и калибровка - это две внутренние структуры сообщений.

Я пытаюсь создать «интерпретатор сообщений», который будетполучить строку XML, декодировать ее и вернуть любую из структур, показанных выше;так что если <messageType> равно 'alignment', интерпретатор сообщений создаст структуру выравнивания и вернет ее.

Итак, в конце концов, я пытаюсь создать шаблонную функцию, которая может возвращать произвольную структуру, основываясь на том, что я прочитал из <messageType>.

Мои цели ясны?мой подход правильный?

Дайте мне знать, если я должен уточнить, или я должен выбрать другой подход.

Ответы [ 4 ]

3 голосов
/ 15 февраля 2012

Я не верю, что функция шаблона имеет смысл.Ваш ввод всегда будет строкой, и C ++ не может дифференцировать сигнатуры функций, основанные только на типе возвращаемого значения - поэтому я не знаю, как шаблон поможет - каким будет аргумент типа?

Iпредложил бы сделать вашу функцию нормальной, которая анализирует messageType и выделяет структуру, основанную на нем - вы можете использовать любые конструкции, которые вы хотите для этого.ваших внутренних классов сообщений из того же пустого базового класса - вы можете затем вернуть указатель на этот базовый класс обратно из вашей функции, и он будет содержать любой созданный тип.

Это хорошая идеявернуть перечисление вместе с указателем в std :: pair, который вы можете использовать для определения созданного правильного производного типа, таким образом вы можете привести результат непосредственно к правильному производному типу с помощью static_cast.

0 голосов
/ 15 февраля 2012

используя QMetaObject :: newInstance, так что вы можете создать QObject *, который впоследствии можно будет преобразовать в ваш класс с помощью dynamic_cast

class MyClass : public QObject{
    public:
    enum Type{ MyClassType = UserType + 1 }
    Q_INVOKABLE MyClass();
}
Q_DECLARE_METATYPE ( MyClass )

затем в вашем коде парсинга XML:

MyClass* myObject = (MyClass*) QMetaType::construct ( MyClass::MyClassType );

И все получится.

0 голосов
/ 15 февраля 2012

Если вы пишете фабричную функцию / функтор для каждого типа, вы можете связать это с messageType (map<string, Factory*> будет достаточно), но что вернуть?

Вы можете вернуть какой-то виддискриминационное объединение, или boost::variant, если вы не возражаете против декодера верхнего уровня в зависимости от всех возможных типов сообщений.

Но что будет делать декодер с этим возвращаемым значением?Если он просто включает тип и вызывает специфичный для типа обратный вызов в каждом случае, вы можете инвертировать управление, напрямую подключив функцию / функтор обратного вызова к фабрике.

Тогда декодер ничего не возвращает, онпросто создает сообщение struct и передает его непосредственно обработчику.

Простая реализация (хорошо, это было больше ввода, чем я думал):

class Decoder
{
public:
  virtual ~Decoder();
  virtual void decode(std::string const &xml) = 0;
};

template <typename Factory, typename Callback>
class SimpleDecoder: public Decoder
{
  Factory factory;
  Callback callback;
public:
  SimpleDecoder(Factory f, Callback c)
  : factory(f), callback(c)
  {}

  void decode(std::string const &xml)
  {
    callback( factory( xml ) );
  }
};

std::map<std::string, Decoder*> factories;

template <typename F, typename C>
void registerSimpleDecoder(std::string const &n, F f, C c)
{
  factories[n] = new SimpleDecoder(f, c);
}

void decodeXmlMessage(std::string const &messageType, std::string const &body)
{
  factories[messageType]->decode(body);
}
0 голосов
/ 15 февраля 2012

Насколько я понимаю, ваши структуры известны в приложении, так что насчёт этого варианта сохранения:

class Message {
public:
    static Message Alignment (alignment_t const &);
    ...
    Type type() const;

    int alignment() const;

private:
    Message (Type t);
    assert_type (Type t, const char *msg) const;

private:
   Type type_;
};

Message Message::Alignment (alignment_t const &alignment) 
{
    Message ret (Type::Alignment);
    ret.alignment_ = alignment;
    return ret;
}

void Message::assert_type (Type t, const char *msg) const
{
    if (type() != t) throw std::runtime_error (msg);
}

int Message::alignment() const
{
    assert_type (Type::Alignment, 
                 "alignment_x() called for non-alignment-message");
    return alignment_;
}

(закодировано без проверки, чтобы дать вам идею)

Это работает без полиморфизма (я использую этот шаблон в компиляторе для языка, подобного LISP, где полиморфные деревья приводят к более сложному коду). Вы можете изменить его так, чтобы он возвращал "alignment_x ()" и так далее, если вам это нравится больше.

Полностью динамические структуры невозможны, и решения, которые пытаются приблизиться, будут довольно сложными. Используйте наиболее приемлемое решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...