1

練習のために、json インタープリターを c++ で作成することにしました。理想的には、json が実際に構造化されている方法でアクセスできるように、マップ、ベクトル、および関連する値の型のツリー状のコンテナーに設定できるようにしたいと考えています。たとえば、次の JSON の例 (json.org から) があるとします。

JSON
{
"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}


C++
jsonobject["menu"]["id"] // returns std::string "file"
jsonobject["menu"]["popup"]["menuitem"] // returns std::vector of std::maps
jsonobject["menu"]["popup"]["menuitem"][0]["value"] // returns std::string "New"

上記の例で、私の最初の問題は、コンテナー内に型が混在していることから生じました。たとえば、上記の json では、「メニュー」は std::map になりますが、一方が文字列を返し、もう一方がベクトルを返すため、キー「id」と「popup」を使用できません。

この問題を回避するために、型のない基本クラスから継承するラッパー テンプレート クラスを作成することにしました。これにより、値への多態的なアクセスが可能になると仮定します。問題は、私ができないことです。ここに私がこれまでに持っているものを示すいくつかのコードがあります:

#include <string>
#include <map>
#include <vector>

class NodeBase {};

template <typename T>
class Node : public BaseNode {};

typedef std::map<std::string, BaseNode*> JSONObject;
template <>
class Node<JSONObject> : public BaseNode {
  public:
    JSONObject value;
    BaseNode* operator[](const std::string key){(value.find(key) != value.end) ? return value[key] : return nullptr}
};

typedef std::vector<BaseNode*> JSONArray;
template <>
class Node<JSONArray> : public BaseNode {
  public:
    JSONArray value;
    BaseNode* operator[](const uint index) {(index < value.size()) ? return value[index] : return nullptr}
};

template <typename T>
class Node : public BaseNode {
  public:
    T value;
};

class RootNode {
  Node<JSONObject> value;
};

int main(void) {
  RootNode root;
  root.insert(std::pair<std::string, BaseNode*>("menu", new Node<JSONObject>)
  // problem!
  // cannot use following code, because BaseNode* does not have access to value :'<
  root["menu"].insert(..)
}

だから私の質問は、どうすればこれを機能させることができるのでしょうか? 私は正しい道を進んでいますが、経験不足から解決策を見ることができませんか、それともこの設計は単に C++ と互換性がないのでしょうか?

4

1 に答える 1

3

興味深いクラスですが、最近boost::property_threeを使用してjsonを解析し、ホイールxDの再発明を回避できたことを嬉しく思います。あなたのライブラリは軽量パーサーとして機能する可能性があるので、この研究に興味があります.

この設計はあまり良くないと思います。ライブラリを使用する人は、特定の値が含まれていることを知らない可能性があります: ハッシュまたは配列. dynamic_castこれは、比較的重い操作である過負荷につながる可能性があります。その結果、ライブラリの「軽量」特性が失われます。

Getすべてのメソッド returnのように、1 つのオブジェクト型表記を使用することをお勧めしますが、動的キャストのような重い操作を行うことなく、質問に答えることNode*ができます。Node*isArray()isHash()

次に、:から継承された同じインターフェイスを持つ必要がありますがNode<JSONObject>、オーバーロードによってキーを受け取ることができます。これにより API が縮小され、ユーザーが配列であることがわかっている場合はインデックスを使用できるようになります。しかし、それは万能薬ではありません。「ライブラリの設計」と呼ばれるものを行う必要があります。Node<JSONArray>BaseNodeBaseNode* operator[](const std::string key)Node<JSONArray>intoperator[]int

全体的に、今はコードを書かないことをお勧めします。いくつかのクラス階層スキーマを書き、いくつかのユース ケースを書きます。これらのユースケースがスキーマにどのように適合するかを見てください。一般に、そのようなライブラリを作成するのは簡単な作業ではなく、「設計」のミスにより、ライブラリが将来使用できなくなる可能性があります。賢明な選択をしてください =) がんばってください!

于 2012-09-25T06:48:06.250 に答える