C++ std::variant,一个包装类和';从…转换为。。。到非标量类型。。。请求';

C++ std::variant,一个包装类和';从…转换为。。。到非标量类型。。。请求';,c++,c++17,variant,C++,C++17,Variant,我有相互递归的变量类型:值、数组和对象。问题的关键在于,当一个变量类型嵌套在一个数组或对象中时,我可以将它指定给一个值,这两个数组或对象都可以包含值。我不能直接赋值。底部的main()。编译器(GNU GCC 7.2)给了我如下错误: error: conversion from 'JSON::Integer {aka long unsigned int}' to non-scalar type 'JSON::Value' requested Value v = Integer( 7 );

我有相互递归的变量类型:值、数组和对象。问题的关键在于,当一个变量类型嵌套在一个数组或对象中时,我可以将它指定给一个值,这两个数组或对象都可以包含值。我不能直接赋值。底部的
main()。编译器(GNU GCC 7.2)给了我如下错误:

error: conversion from 'JSON::Integer {aka long unsigned int}' to non-scalar type 'JSON::Value' requested
  Value v = Integer( 7 );
奇怪的是,它没有提供任何关于作业操作员候选人或其他任何信息。此外,我不清楚我在Value中定义的赋值运算符是如何影响这个问题的。完整的工作示例代码如下。将其中一个变量类型直接赋值给
main()
中的值类型会导致编译器错误,就像上面针对
Integer
类型的错误一样

提前谢谢

对象类
#ifndef JSON_OBJECT_HPP
#定义JSON\u对象\u HPP
#包括
#包括
#包括
#包括“Value.hpp”
名称空间JSON{
类对象{
公众:
使用Key=std::string;
私人:
使用值\u t=std::无序\u映射;
价值观;
公众:
Object()=默认值;
值和运算符[](键常量和键){
autoit=values.emplace(key,Value());
返回它。第一->第二;
}
值常量和运算符[](键常量和键)常量{
自动it=值。查找(键);
返回->秒;
}
布尔有_键(键常量和键常量){
自动it=值。查找(键);
返回它!=values.end();
}
布尔运算符==(对象常量和rhs)常量{
返回值==rhs.values;
}
值\u t::常量\u迭代器begin()常量{
返回值。begin();
}
值:常量迭代器end()常量{
返回值。end();
}
值\u t::迭代器begin(){
返回值。begin();
}
值\u t::迭代器结束(){
返回值。end();
}
};
布尔运算符==(对象常量和lhs、对象常量和rhs){
返回lhs。运算符==(rhs);
}

std::ostream&operator这是一个糟糕的问题,有一个令人尴尬的疏忽
是初始化,而不是赋值。提供适当的构造函数解决了问题。为了完整性,更正后的代码如下。它在GNU GCC 7.2下编译并运行良好

对象类
#ifndef JSON_OBJECT_HPP
#定义JSON\u对象\u HPP
#包括
#包括
#包括
#包括“Value.hpp”
名称空间JSON{
类对象{
公众:
使用Key=std::string;
私人:
使用值\u t=std::无序\u映射;
价值观;
公众:
Object()=默认值;
值和运算符[](键常量和键){
autoit=values.emplace(key,Value());
返回它。第一->第二;
}
值常量和运算符[](键常量和键)常量{
自动it=值。查找(键);
返回->秒;
}
布尔有_键(键常量和键常量){
自动it=值。查找(键);
返回它!=values.end();
}
布尔运算符==(对象常量和rhs)常量{
返回值==rhs.values;
}
值\u t::常量\u迭代器begin()常量{
返回值。begin();
}
值:常量迭代器end()常量{
返回值。end();
}
值\u t::迭代器begin(){
返回值。begin();
}
值\u t::迭代器结束(){
返回值。end();
}
};
布尔运算符==(对象常量和lhs、对象常量和rhs){
返回lhs。运算符==(rhs);
}

std::ostream&operatorWell,
JSON::Value
确实没有提供任何将采用
JSON::Integer
的构造函数。您到底希望
Value v=Integer(7);
做什么?这是一个初始化,而不是赋值(如果您希望使用
operator=
).@IgorTandetnik嗯……那太尴尬了。当然,你一针见血。这是很多代码。请提供一个,强调最小值。@Barry抱歉。这让我很难过。下次我会努力做得更好。整个“相互递归位”这让我觉得删除任何代码都可能会影响建议答案的通用性,尽管显然给出了最终解决方案,但事实并非如此。
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP

#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"

namespace JSON {
    class Object {
        public:
            using Key = std::string;

        private:
            using values_t = std::unordered_map<Key,Value>;
            values_t values;

        public:
            Object() = default;

            Value & operator[]( Key const & key ) {
                auto it = values.emplace( key, Value() );
                return it.first->second;
            }

            Value const & operator[]( Key const & key ) const {
                auto it = values.find( key );
                return it->second;
            }
            bool has_key( Key const & key ) const {
                auto it = values.find( key );
                return it != values.end();
            }
            bool operator==( Object const & rhs ) const {
                return values == rhs.values;
            }
            values_t::const_iterator begin() const {
                return values.begin();
            }
            values_t::const_iterator end( ) const {
                return values.end();
            }
            values_t::iterator begin() {
                return values.begin();
            }
            values_t::iterator end() {
                return values.end();
            }
    };

    bool operator==( Object const & lhs, Object const & rhs ) {
        return lhs.operator==( rhs );
    }

    std::ostream & operator<<( std::ostream & os, Object const & object ) {
        os << '{';
        auto begin = object.begin();
        auto end = object.end();
        if( begin != end ) {
            os << std::quoted( begin->first ) << ':' << begin->second;
        }
        while( ++begin != end ) {
            os << ',' << std::quoted( begin->first ) << ':' << begin->second;
        }
        os << '}';
    }
}

#endif
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP

#include <vector>
#include "types.hpp"
#include "Value.hpp"

namespace JSON {
    std::ostream & operator<<( std::ostream &, Value & );

    class Array {
        private:
            using values_t = std::vector<Value>;
            values_t values;
        public:
            using Key = values_t::size_type;
            Array() = default;
            Value & operator[]( Key key ) {
                if( !has_key( key ) ) {
                    values.resize( key + 1 );
                }
                return values[key];
            }
            Value const & operator[]( Key key ) const {
                return values[key];
            }
            bool has_key( Key key ) const {
                return key < values.size();
            }
            bool operator==( Array const & rhs ) const {
                return values == rhs.values;
            }
            values_t::const_iterator begin() const {
                return values.begin();
            }
            values_t::const_iterator end( ) const {
                return values.end();
            }
            values_t::iterator begin() {
                return values.begin();
            }
            values_t::iterator end() {
                return values.end();
            }
    };

    bool operator==( Array const & lhs, Array const & rhs ) {
        return lhs.operator==( rhs );
    }

    std::ostream & operator<<( std::ostream & os, Array const & array ) {
        os << '[';
        auto begin = array.begin();
        auto end = array.end();
        if( begin != end ) {
            os << *begin;
        }
        while( ++begin != end ) {
            os << ',' << *begin;
        }
        os << ']';
    }
}

#endif
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP

#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"

namespace JSON {
    class Object;
    class Array;
    bool operator==( Object const & lhs, Object const & rhs );
    bool operator==( Array const & lhs, Array const & rhs );
    std::ostream & operator<<( std::ostream &, Object const & object );
    std::ostream & operator<<( std::ostream &, Array const & array );
    template<class T> struct always_false : std::false_type {};

    class Value {
        private:
            using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
            variant_t data;
            friend std::ostream & operator<<( std::ostream & os, Value const & value );
        public:
            Value() = default;
            bool operator==( Value const & rhs ) const {
                return std::visit(
                        []( auto && lhs, auto && rhs ) -> bool {
                            using lhsT = std::decay_t<decltype( lhs )>;
                            using rhsT = std::decay_t<decltype( rhs )>;
                            if constexpr ( std::is_same_v< lhsT, rhsT> ) {
                                if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
                                    return lhs.get() == rhs.get();
                                } else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
                                        return lhs.get() == rhs.get();
                                } else {
                                    return lhs == rhs;
                                }
                            } else {
                                return false;
                            }
                        },
                        data,
                        rhs.data
                        );
            }
            Value & operator=( String const & rhs ) {
                data = rhs;
                return *this;
            }
            Value & operator=( Integer const & rhs ) {
                data = rhs;
                return *this;
            }
            Value & operator=( Object const & rhs ) {
                data = rhs;
                return *this;
            }
            Value & operator=( Array const & rhs ) {
                data = rhs;
                return *this;
            }

    };

    std::ostream & operator<<( std::ostream & os, Value const & value ) {
        std::visit(
                [&os]( auto && arg ) {
                    using T = std::decay_t<decltype( arg )>;
                    if constexpr ( std::is_same_v< T, Undefined > ) {
                        os << "undefined";
                    } else if constexpr ( std::is_same_v< T, String > ) {
                        os << std::quoted( arg );
                    } else if constexpr ( std::is_same_v< T, Integer > ) {
                        os << arg;
                    } else if constexpr ( std::is_same_v< T, Number > ) {
                        os << arg;
                    } else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
                        os << arg.get();
                    } else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
                        os << arg.get();
                    } else if constexpr ( std::is_same_v< T, Boolean > ) {
                        os << (arg == false ? "false" : "true");
                    } else if constexpr ( std::is_same_v< T, Null > ) {
                        os << "null";
                    } else {
                        static_assert( always_false<T>::value, "non-exhaustive visitor" );
                    }
                },
                value.data
                );
    }
}

#endif
#ifndef TYPES_HPP
#define TYPES_HPP

namespace JSON {
    template <typename Tag> struct Literal {
        bool operator==( Literal const & ) const {
            return true;
        }
        bool operator<( Literal const & ) const {
            return false;
        }
    };
    using String = std::string;
    using Integer = uint64_t;
    using Number = double;
    class Object;
    class Array;
    using Boolean = bool;
    using Null = Literal<struct tag_null>;
    using Undefined = Literal<struct tag_undefined>;
}

#endif
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"

using namespace JSON;

int main() {
    Object o;
    o["fun"] = "what?"; // compiles fin
    o["stuff"] = "yeah!"; // compiles fine
    o["inttest"] = Integer( 44 ); // compiles fine
    Array a;
    a[2] = "yo"; // compiles fine
    a[3] = Integer( 6 ); // compiles fine
    o["arrtest"] = a;
//  Value v = a; // fails to compile
    Value v = Integer( 7 ); // fails to compile
    std::cout << v;
    std::cout << o << "\n";
    std::cout << a << "\n";
    return 0;
}
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP

#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"

namespace JSON {
    class Object {
        public:
            using Key = std::string;

        private:
            using values_t = std::unordered_map<Key,Value>;
            values_t values;

        public:
            Object() = default;

            Value & operator[]( Key const & key ) {
                auto it = values.emplace( key, Value() );
                return it.first->second;
            }

            Value const & operator[]( Key const & key ) const {
                auto it = values.find( key );
                return it->second;
            }
            bool has_key( Key const & key ) const {
                auto it = values.find( key );
                return it != values.end();
            }
            bool operator==( Object const & rhs ) const {
                return values == rhs.values;
            }
            values_t::const_iterator begin() const {
                return values.begin();
            }
            values_t::const_iterator end( ) const {
                return values.end();
            }
            values_t::iterator begin() {
                return values.begin();
            }
            values_t::iterator end() {
                return values.end();
            }
    };

    bool operator==( Object const & lhs, Object const & rhs ) {
        return lhs.operator==( rhs );
    }

    std::ostream & operator<<( std::ostream & os, Object const & object ) {
        os << '{';
        auto begin = object.begin();
        auto end = object.end();
        if( begin != end ) {
            os << std::quoted( begin->first ) << ':' << begin->second;
        }
        while( ++begin != end ) {
            os << ',' << std::quoted( begin->first ) << ':' << begin->second;
        }
        os << '}';
    }
}

#endif
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP

#include <vector>
#include "types.hpp"
#include "Value.hpp"

namespace JSON {
    std::ostream & operator<<( std::ostream &, Value const & );

    class Array {
        private:
            using values_t = std::vector<Value>;
            values_t values;
        public:
            using Key = values_t::size_type;
            Array() = default;
            Value & operator[]( Key key ) {
                if( !has_key( key ) ) {
                    values.resize( key + 1 );
                }
                return values[key];
            }
            Value const & operator[]( Key key ) const {
                return values[key];
            }
            bool has_key( Key key ) const {
                return key < values.size();
            }
            bool operator==( Array const & rhs ) const {
                return values == rhs.values;
            }
            values_t::const_iterator begin() const {
                return values.begin();
            }
            values_t::const_iterator end( ) const {
                return values.end();
            }
            values_t::iterator begin() {
                return values.begin();
            }
            values_t::iterator end() {
                return values.end();
            }
    };

    bool operator==( Array const & lhs, Array const & rhs ) {
        return lhs.operator==( rhs );
    }

    std::ostream & operator<<( std::ostream & os, Array const & array ) {
        os << '[';
        auto begin = array.begin();
        auto end = array.end();
        if( begin != end ) {
            os << *begin;
        }
        while( ++begin != end ) {
            os << ',' << *begin;
        }
        os << ']';
    }
}

#endif
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP

#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"

namespace JSON {
    class Object;
    class Array;
    bool operator==( Object const & lhs, Object const & rhs );
    bool operator==( Array const & lhs, Array const & rhs );
    std::ostream & operator<<( std::ostream &, Object const & object );
    std::ostream & operator<<( std::ostream &, Array const & array );
    template<class T> struct always_false : std::false_type {};

    class Value {
        private:
            using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
            variant_t data;
            friend std::ostream & operator<<( std::ostream & os, Value const & value );
        public:
            Value() = default;
            template <typename T> Value( T const & rhs ) : data( rhs ) {}
            bool operator==( Value const & rhs ) const {
                return std::visit(
                        []( auto && lhs, auto && rhs ) -> bool {
                            using lhsT = std::decay_t<decltype( lhs )>;
                            using rhsT = std::decay_t<decltype( rhs )>;
                            if constexpr ( std::is_same_v< lhsT, rhsT> ) {
                                if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
                                    return lhs.get() == rhs.get();
                                } else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
                                        return lhs.get() == rhs.get();
                                } else {
                                    return lhs == rhs;
                                }
                            } else {
                                return false;
                            }
                        },
                        data,
                        rhs.data
                        );
            }
    };

    std::ostream & operator<<( std::ostream & os, Value const & value ) {
        std::visit(
                [&os]( auto && arg ) {
                    using T = std::decay_t<decltype( arg )>;
                    if constexpr ( std::is_same_v< T, Undefined > ) {
                        os << "undefined";
                    } else if constexpr ( std::is_same_v< T, String > ) {
                        os << std::quoted( arg );
                    } else if constexpr ( std::is_same_v< T, Integer > ) {
                        os << arg;
                    } else if constexpr ( std::is_same_v< T, Number > ) {
                        os << arg;
                    } else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
                        os << arg.get();
                    } else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
                        os << arg.get();
                    } else if constexpr ( std::is_same_v< T, Boolean > ) {
                        os << (arg == false ? "false" : "true");
                    } else if constexpr ( std::is_same_v< T, Null > ) {
                        os << "null";
                    } else {
                        static_assert( always_false<T>::value, "non-exhaustive visitor" );
                    }
                },
                value.data
                );
    }
}

#endif
#ifndef JSON_TYPES_HPP
#define JSON_TYPES_HPP

namespace JSON {
    template <typename Tag> struct Literal {
        bool operator==( Literal const & ) const {
            return true;
        }
        bool operator<( Literal const & ) const {
            return false;
        }
    };
    using String = std::string;
    using Integer = uint64_t;
    using Number = double;
    class Object;
    class Array;
    using Boolean = bool;
    using Null = Literal<struct tag_null>;
    using Undefined = Literal<struct tag_undefined>;
}

#endif
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"

using namespace JSON;

int main() {
    Object o;
    o["fun"] = "what?";
    o["stuff"] = "yeah!";
    o["inttest"] = Integer( 44 );
    Array a;
    a[2] = "yo";
    a[3] = Integer( 6 );
    o["arrtest"] = a;
//  Value v = a;
    Value v = Integer( 7 );
    std::cout << v << "\n";
    std::cout << o << "\n";
    std::cout << a << "\n";
    return 0;
}