2012-02-15 15 views
1

他のアプリケーションからメッセージを受信するアプリケーションがあります。これらのメッセージはXML形式の文字列になり、<messageType>タグが含まれます。メッセージタイプは、このメッセージを一種の内部メッセージとして識別します。次のコードは、私の内部メッセージ構造を示しています。テンプレートクラスC++/Qt

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

} 

アライメントとキャリブレーションは、2つの内部メッセージ構造です。

私がしようとしているのは、XML文字列を受け取ってそれをデコードし、上記の構造体のいずれかを返す「メッセージインタープリタ」を構築することです。したがって、<messageType>が 'アライメント'の場合、メッセージインタープリタはアラインメント構造体を構築し、それを返します。

最終的には、<messageType>から読み込んだものに基づいて、任意の構造体を返すテンプレート関数を作成しようとしています。

私の目的は明確ですか?私のアプローチは正しいものですか?

明確にすべきか、別のアプローチをとるべきかを教えてください。

答えて

3

私はテンプレート機能が理にかなっているとは思いません。あなたの入力は常に文字列になり、C++では戻り値の型だけに基づいて関数のシグネチャを区別することができません - したがって、テンプレートがどのように役立つのかわかりません - 型引数は何ですか?

私はあなたの関数をmessageTypeを解析し、それに基づいて構造体を割り当てる通常の関数にすることをお勧めします。これに対して必要な構造体を使用できます。

私の考えでは、内部のメッセージクラスをすべて同じ空の基底クラスから派生させることができます。その基底クラスのポインタを関数から戻すことができます。タイプが作成されました。

正しい派生型に直接結果をキャストできるように、生成された正しい派生型を判別するために使用できるstd :: pairの列挙型をポインタとともに返すことをお勧めしますstatic_castを使ってあなたの構造は、アプリケーション内で知られている私は、それを理解したよう

0

ので、これについてのバリアント保存するもの:

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

これは多型なしで動作

(あなたのアイデアを与えるために確認せずにコード化された)(Iを多形木がより複雑なコードになるLISPのような言語のコンパイラでこのパターンを使用してください)。あなたはそれを変更することができます "align_x()"など、あなたがもっと好きな場合に戻ります。

完全に動的な構造は不可能であり、近づくようになるソリューションはやや複雑になります。最もメンテナンス可能なソリューションを使用してください。

0

ファクトリファンクション/ファンクタをタイプごとに記述する場合は、messageTypemap<string, Factory*>で十分です)に関連付けることができますが、返すものは何ですか?

可能なすべてのメッセージタイプに応じてトップレベルのデコーダを気にしない場合は、何らかの種類の識別ユニオンまたはboost::variantを返すことができます。

しかし、この戻り値を使用するデコーダは何ですか?型をオンにしてそれぞれの型固有のコールバックを呼び出すだけであれば、コールバック関数/ファンクタを直接ファクトリに付加す​​ることで制御を逆転させることができます。

デコーダは何も返さず、ただメッセージstructを作成し、直接ハンドラに渡します。

シンプルな実装(OK、それは私が思った以上にタイピングした):、

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

QMetaObject ::のnewInstanceを使用して、あなたは

dynamic_castを使用して、あなたのクラスに後から変換することができQObjectの*を作成することができますので、
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); 

物事のwiうまくいくでしょう。

関連する問題