std::variant,一个包装类,以及“从……到非标量类型的转换……请求”

rg6

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

这是一个令人尴尬的疏忽的糟糕问题。正如评论者所指出的,有问题的行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;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

请求从'std :: vector <AdjacencyData>(*)()'转换为非标量类型'std :: vector <AdjacencyData>'

使用类型超集将std :: variant转换为另一个std :: variant

我该如何解决错误:请求从“ void”转换为非标量类型“ std :: vector <int>”

错误:请求从“const char”转换为非标量类型“std::string”{aka 'std::__cxx11::basic_string<char>'}

从std :: future <void>到非标量std :: future <bool>的转换引发错误

创建一个Variant类和std :: map <Variant,Variant>

获取一个std :: tuple元素作为std :: variant

std :: bind到包含多种std :: function类型的std :: variant

从请求到非标量类型的转换(功能)

错误:从std :: chrono :: time_point浮点数转换为非标量类型long int

static_assert一个类型在std :: variant的可接受类型之中

实现std :: variant转换构造函数-或:如何从参数包中查找所有从T到Ti的所有转换的第一个重载

定义一个函数以返回指定类型的std :: variant C ++

将std :: variant转换为模板类实例的std :: tuple

从std :: variant到std :: visit的可能类型返回值

如何将 std::variant 减少到一个值?

返回类型std :: optional <std :: variant <... >>

如何将std :: variant的元素复制到另一个variant-type的变量

默认从索引构造一个std :: variant

为std :: variant提供一个运算符==

请求从“const char[2]”到非标量类型“Persona”的转换

c ++从“ B”到非标量类型“ A”的转换请求

std :: string到std :: regex

比较std :: variant类型实例

如何迭代std :: variant的类型?

将一个std :: optional转换为另一个std :: optional

为什么与比较类不在同一个命名空间中时,std :: variant无法找到operator <()

构造std :: variant时,禁用从指针类型到bool的隐式转换的最佳方法是什么?

为什么std :: optional :: operator =(U &&)要求U为非标量类型?