代码之家  ›  专栏  ›  技术社区  ›  rg6

variant,一个包装类,和“从…的转换”。。。到非标量类型。。。请求'

  •  2
  • rg6  · 技术社区  · 8 年前

    我有相互递归的变量类型:值、数组和对象。问题的关键在于,当一个变量类型嵌套在一个数组或对象中时,我可以将它指定给一个值,这两个数组或对象都可以包含值。我不能直接赋值。这个 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中定义的赋值运算符是如何影响这个问题的。完整的工作示例代码如下。将其中一个变量类型直接赋值给 导致编译器错误,就像上面针对 Integer 类型

    提前感谢!

    #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;
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   rg6    8 年前

    这是一个糟糕的问题,有一个令人尴尬的疏忽。正如评论者所指出的那样,在 main() 是初始化而不是赋值。提供合适的施工人员解决了问题。为了完整性起见,下面是更正的代码。它在GNU GCC 7.2下编译并运行良好。

    对象类

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