C++相互递归变体类型(再次)

rg6*_*rg6 6 c++ json boost boost-variant

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

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

以下是"如果希望是马,乞丐会骑"版本的代码,这是为了清楚地说明意图,但显然是因为在任何声明存在之前使用类型而被破坏.我想避免在类型中多次指定相同的信息(即Array,Object和Value不应该需要重复的类型规范).我还想避免任何不必要的高运行时间成本.

#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 );
        }
        ...
};
Run Code Online (Sandbox Code Playgroud)

如你所见,我包括recursive_wrapper标题.我尝试过各种boost :: make_recursive_variant和boost :: recursive_wrapper的调用,但我总是遇到编译器错误.我没有看到C++ Mutually Recursive Variant Type的答案如何解决这个问题,因为在每次尝试中,我都会遇到编译器错误(来自gcc ++ 5.3和LLVM/clang ++ 3.8)几乎完全引用Boost,它基本上归结为不可转换的类型或声明冲突或不存在.我会在这里尝试我的一个尝试以及特定的编译器错误消息,但我不知道有多少尝试使用.

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

提前致谢!

编辑

仅仅基于下面接受的答案,这里是类型及其用法的工作框架的示例.

#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;
}
Run Code Online (Sandbox Code Playgroud)

seh*_*ehe 6

你可以使用recursive_variant_占位符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>;
Run Code Online (Sandbox Code Playgroud)

现场演示

Live On Coliru

正如您所看到的那样,代码中没有未实现的位(永远不会写函数缺少返回语句!).还要注意控制流程get和私有访问者实现的简化.

#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() {}
Run Code Online (Sandbox Code Playgroud)

CAVEATS

  • 请注意,您不应该使用void*Null,因为所有不必要的隐式转换都是如此
  • 请注意,您可能不应该使用unordered_map因为

    • 一些JSON实现允许重复的属性名称
    • 一些JSON应用程序依赖于属性的顺序

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