C ++相互递归变体类型(再次) [英] C++ Mutually Recursive Variant Type (Again)

查看:119
本文介绍了C ++相互递归变体类型(再次)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个与此处所述类似的问题: C ++相互递归变体类型

I have a problem similar to that described here: C++ Mutually Recursive Variant Type

我正在尝试用C ++创建JSON表示形式。许多库已经提供了非常快的 excellent JSON表示形式和解析器,但是我并没有重新发明这个轮子。我需要创建一个在特定条件下支持某些空间优化的C ++ JSON表示形式。简而言之,当且仅当JSON数组包含同质数据,而不是将每个元素存储为as肿的变量类型时,我才需要本机类型的紧凑存储。我还需要支持异构数组和标准的嵌套JSON对象。

I am trying to create a JSON representation in C++. Many libraries already offer excellent JSON representations and parsers that are very fast, but I am not reinventing this wheel. I need to create a C++ JSON representation that supports certain space optimizations under specific conditions. In short, if and only if a JSON array contains homogenous data, rather than storing every element as bloated variant types, I need compact storage of native types. I also need to support heterogeneous arrays and standard nested JSON objects.

下面是代码的如果希望是马,乞g会骑的意思是可以清楚地说明意图,但由于在声明之前使用了类型,因此显然被破坏了。我想避免在类型中多次指定相同的信息(即数组,对象和值不应要求重复的类型规范)。我还希望避免不必要的高运行时间成本。

The following is the "if wishes were horses, beggars would ride" version of the code, which is meant to clearly illustrate intent, but is obviously broken because types are used before any declaration exists. I want to avoid specifying the same information multiple times in types (i.e. Array, Object, and Value should not require duplicated type specifications). I also want to avoid any unnecessarily high run-time costs.

#include <string>
#include <unordered_map>
#include <vector>
#include <boost/variant.hpp>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>

class JSONDocument {
    public:
        using String = std::string;
        using Integer = long;
        using Float = double;
        using Boolean = bool;
        using Null = void *;
        using Key = std::string;
        using Path = std::string;
        using Value = boost::variant<
                Null,
                String,
                Integer,
                Float,
                Boolean,
                Object,
                Array
                >;
        using Object = std::unordered_map<Key,Value>;
        using Array = boost::variant<
                std::vector<Null>,
                std::vector<String>,
                std::vector<Integer>,
                std::vector<Float>,
                std::vector<Boolean>,
                std::vector<Value> >;
    private:
        Value root;
        class value_traversal_visitor : public boost::static_visitor<Value> {
            public:
                value_traversal_visitor( Path path ) : path(path) {}
                Value operator()( Null x ) const {
                    if( path.empty() ) {
                        return x;
                    }
                    // otherwise throw ...
                }
                Value operator()( String x ) const {
                    if( path.empty() ) {
                        return x;
                    }
                }
                ...
                // special handling for Array and Object types
            private:
                Path path;
        };
    public:
        Value get( Path path ) {
            return boost::apply_visitor( value_traversal_visitor( path ), root );
        }
        ...
};

如您所见,我包括 recursive_wrapper 标头。我已经尝试了boost :: make_recursive_variant和boost :: recursive_wrapper的各种调用,但是我总是会遇到编译器错误。我没有看到 C ++相互递归变体类型的答案如何解决这一问题,因为在每次尝试,我都会得到编译器错误(来自gcc ++ 5.3和LLVM / clang ++ 3.8),这些错误几乎都引用了Boost,它实际上归结为不可转换的类型或声明冲突或不存在的类型。我会在这里放上我的尝试之一以及特定的编译器错误消息,但我不知道要使用多少尝试。

As you can see, I am including the recursive_wrapper header. I have tried various invocations of boost::make_recursive_variant and boost::recursive_wrapper, but I always get compiler errors. I do not see how the answer from C++ Mutually Recursive Variant Type solves this, because in every attempt, I get compiler errors (from both gcc++ 5.3 and LLVM/clang++ 3.8) that almost exclusively reference Boost that essentially boil down to types not being convertible or declarations either conflicting or not existing. I would put one of my attempts along with specific compiler error messages here, but I wouldn't know which of the many attempts to use.

我希望有人可以让我走上正确的道路...

I'm hoping somebody can set me on the right path...

谢谢!

仅以下面接受的答案为基础,下面是有关类型及其用法的工作框架示例。

Just to build on the accepted answer below, here is an example of a working skeleton for the types and their usages.

#include <string>
#include <unordered_map>
#include <vector>
#include <boost/variant.hpp>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>

using String = std::string;
using Integer = long;
using Float = double;
using Boolean = bool;
using Key = std::string;

using Value = boost::make_recursive_variant<
        String,
        Integer,
        Float,
        Boolean,
        std::unordered_map<Key, boost::recursive_variant_>,
        boost::variant<std::vector<String>,std::vector<Integer>,std::vector<Float>,std::vector<Boolean>,std::vector<boost::recursive_variant_> >
        >::type;

using Object = std::unordered_map<Key, Value>;

using Array = boost::variant<std::vector<String>,std::vector<Integer>,std::vector<Float>,std::vector<Boolean>,std::vector<Value> >;

int main( int argc, char* argv[] ) {
    Value v;
    v = static_cast<Integer>( 7 );
    Object o;
    v = o;
    Array a = std::vector<Integer>( 3 );
    v = a;
    return 0;
}


推荐答案

您可以使用 recursive_variant _ 占位符,带有 make_recursive_variant

You could just use recursive_variant_ placeholder with make_recursive_variant.

这是要点:

using Value   = boost::make_recursive_variant<
    Null, 
    String, 
    Integer, 
    Float, 
    Boolean,
    std::unordered_map<Key, boost::recursive_variant_>, // Object
    std::vector<boost::recursive_variant_>              // Array
>::type;
using Object = std::unordered_map<Key, Value>;
using Array = boost::variant<Value>;



实时演示



< kbd> 在Coliru上直播

如您所见,代码中有未实现的位(切勿写缺少返回语句的函数!)。还请注意 get 的控制流和私有访客实现的简化。

As you can see there's unimplemented bits in the code (never write functions missing return statements!). Also note the simplifications in control flow for get and the private visitor implementation.

#include <boost/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/variant/variant.hpp>
#include <string>
#include <unordered_map>
#include <vector>

class JSONDocument {
  public:
    struct Null { constexpr bool operator==(Null) const { return true; } };
    using String  = std::string;
    using Integer = long;
    using Float   = double;
    using Boolean = bool;
    using Key     = std::string;
    using Path    = std::string;
    using Value   = boost::make_recursive_variant<
        Null, 
        String, 
        Integer, 
        Float, 
        Boolean,
        std::unordered_map<Key, boost::recursive_variant_>, // Object
        std::vector<boost::recursive_variant_>              // Array
    >::type;
    using Object = std::unordered_map<Key, Value>;
    using Array = boost::variant<Value>;

  private:
    Value root;

    struct value_traversal_visitor {
        Path path;
        using result_type = Value;

        result_type operator()(Value const &x) const {
            if (path.empty()) {
                return x;
            }
            return boost::apply_visitor(*this, x);
        }

        result_type operator()(Null)           const { throw std::invalid_argument("null not addressable"); }
        result_type operator()(String const &) const { throw std::invalid_argument("string not addressable"); }

        // special handling for Array and Object types TODO
        template <typename T> result_type operator()(T &&) const { return Null{}; }
    };

  public:
    Value get(Path path) { return value_traversal_visitor{path}(root); }
};

int main() {}



旅行者




  • 请注意,您不应该将 void * 用作Null,因为各种形式的不需要的隐式转换

  • 请注意,您可能不应该使用 unordered_map ,因为

    CAVEATS

    • Note that you should NOT use void* for Null because all manner of unwanted implicit conversions
    • Note that you should probably not use unordered_map because


      • 某些JSON实现允许重复的属性名称

      • 某些JSON应用程序取决于属性的顺序

      另请参见 https://github.com/sehe/spirit-v2-json/blob/master/json.hpp#L37

      这篇关于C ++相互递归变体类型(再次)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆