模板类 C++ /Qt

发布于 2025-01-06 01:52:08 字数 952 浏览 1 评论 0原文

我有一个应用程序将接收来自另一个应用程序的消息。这些消息将是 XML 格式的字符串,并且它们将包含 标记。消息类型将将此消息标识为内部消息的类型。以下代码显示了我的内部消息结构。

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 字符串,对其进行解码并返回上面显示的任何一个结构;因此,如果 是“alignment”,消息解释器将构建一个对齐结构并返回该结构。

所以最终,我试图创建一个模板函数,它可以根据我从 读取的内容返回任意结构。

我的目标明确吗?我的方法正确吗?

让我知道是否应该澄清,或者是否应该采取不同的方法。

I have an application which will be receiving messages from another application. These messages will be XML fomatted strings, and they will contain a <messageType> tag. The message type will identify this message as a type of internal message. The following code shows my internal message structures.

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;
};

}

alignment and calibration are the two internal message structures.

What I'm trying to do is build a 'message interpreter' which will receive an XML string, decode it and return any one of the structs shown above; so if the <messageType> is 'alignment', the message interpreter will build an alignment struct, and return that.

So ultimately, I'm trying to make a template function, which can return an arbitrary struct, based on what i read in from <messageType>.

Are my objectives clear? is my approach the right one?

Let me know if I should clarify, or if I should take a different approach.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

渔村楼浪 2025-01-13 01:52:08

我不认为模板函数有意义。您的输入始终是一个字符串,而 C++ 无法仅根据返回类型来区分函数签名 - 所以我不知道模板有何帮助 - 类型参数是什么?

我建议让你的函数成为一个普通的函数,解析出 messageType 并根据它分配一个结构 - 你可以使用任何你想要的结构。

诀窍是(在我看来)从同一个空基类派生所有内部消息类 - 然后您可以从函数返回指向该基类的指针,并且它将保存创建的任何类型。

最好在 std::pair 中返回一个枚举和指针,您可以使用它来确定创建的正确派生类型,这样您就可以使用 static_cast 将结果直接转换为正确的派生类型。

I don't believe a template function makes sense. Your input is always going to be a string, and C++ can't differentiate function signatures based on return type alone - so I don't know how a template would help - what would the type argument be?

I'd suggest making your function a normal one that parses out the messageType and allocates a struct based on it - you can use whatever constructs you want for this.

The trick would be (in my mind) to derive all of your internal-message-classes from the same empty base class - you could then return a pointer to that base class back from your function, and it will hold whatever type got created.

It be a good idea to return an enumeration along with the pointer in a std::pair which you can use to determine the correct derived type that was created, that way you can cast the result directly to the correct derived type with a static_cast.

新人笑 2025-01-13 01:52:08

据我了解,您的结构在应用程序中是已知的,那么这个保存变体怎么样:(

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()”等。

完全动态的结构是不可能的,并且试图接近的解决方案将相当复杂。使用最易于维护的解决方案。

As I understand it your structures are known within the application, so what about this save variant:

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_;
}

(coded without verification to give you the idea)

This works without polymorphism (I use this pattern in a compiler for a LISP like language, where polymorphic trees would result in more complicated code). You can change it to return "alignment_x()" and so on, if you like that more.

Fully dynamic structures are not possible, and solutions that try to come near will be rather complicated. Use the most-maintainable solution.

椵侞 2025-01-13 01:52:08

如果您为每种类型编写一个工厂函数/函子,则可以将其与 messageType 关联起来(map 就足够了),但是要做什么返回?

如果您不介意顶级解码器取决于所有可能的消息类型,则可以返回某种可区分的联合或 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);
}

If you write a factory function/functor for each type, you can associate that with the messageType (map<string, Factory*> will be sufficient), but what to return?

You can return some kind of discriminated union, or boost::variant, if you don't mind the top-level decoder depending on all possible message types.

But, what is the decoder going to do with this return value? If it just switches on the type and calls a type-specific callback in each case, you could invert control by attaching a callback function/functor to the factory directly.

Then the decoder doesn't return anything, it just constructs the message struct and passes it directly to a handler.

Simple implementation (OK, that was more typing than I thought):

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);
}
想挽留 2025-01-13 01:52:08

使用dynamic_cast 将其转换为您的类

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

使用 QMetaObject::newInstance,因此您可以创建一个 QObject*,然后可以在您的 XML 解析代码中

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

:事情就会解决。

using QMetaObject::newInstance, so you can create a QObject* that can be converted afterwards to your class using dynamic_cast

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

then, in your XML Parsing Code:

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

And things will work out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文