zoukankan      html  css  js  c++  java
  • C++ 之 Python 字典类型实现

    变体类型 std::variant

    在此之前需要先介绍一下类模板std::variant,其表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误情况下无值。与union在聚合初始化中的行为一致, 若 variant 保有某个对象类型 T 的值,则直接于 variant 的对象表示中分配 T 的对象表示。不允许 variant 分配额外的(动态)内存。简单来说就是一个可变类型的变量,其获取方法跟元组的第一个获取方法类似。代码如下

    #include <variant>
    #include <string>
    #include <cassert>
     
    int main()
    {
        std::variant<int, float> v, w;
        v = 12; // v 含 int
        int i = std::get<int>(v);
        w = std::get<int>(v);
        w = std::get<0>(v); // 与前一行效果相同
    }
    

    更加优秀的状态是std::visitoverloaded模板函数相互配合实现,代码如下:

    #include <variant>
    #include <iostream>
    #include <sstream>
    #include <string>
    
    template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
    template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; 
    
    int main() {
    	std::stringstream convert;
    	std::variant<int, long long int, std::string, double> value = 12.3;
    	std::visit(overloaded{
    	        [&convert](int value) { convert << value << 'i'; },
    	        [&convert](long long int value) { convert << value << 'i'; },
    	        [&convert](double value) { convert << value; },
    	        [&convert](const std::string &value) { convert << '"' << value << '"'; },
    	}, value);
    	std::cout << convert.str();
    }
    

    如果看懂了,你肯定感觉很惊艳。不过作为一个入门级选手的我,属实看不懂。首先是overload就没看懂,不错是template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; 模板参数的自动推导,如果你知道这是类型推导的一步,那已经明白1/3了。

    [&convert](int value) { convert << value << 'i'; },
    [&convert](long long int value) { convert << value << 'i'; },
    [&convert](double value) { convert << value; },
    [&convert](const std::string &value) { convert << '"' << value << '"'; }
    

    这四句话都是如果不明白Lambda 表达式可以查看博文C++ 11 新特性总结,而Lambda 表达式是一个函数对象,其作为overload参数输入,会使得编译器根据自动推导命令,直接将其类作为模板参数表实现类型的声明即获得一个类overloaded<Lambda1,Lambda2,Lambda3>

    接下来是using的变长声明using 声明还挺长一段,详细内容可以查看C++ 中文指南,简单来说,就是直接将父类中的函数直接拿来用,效果就像不是继承而来,在类内自己实现的。这样就有一个效果,如果父类和子类具有同名函数,便形成了函数重载。所以这里的using Ts::operator()...是将所有根据Lambda表达式所获取的继承类Ts()运算符函数直接拿来用,并且由于函数名一样出现类似函数重载的效果。

    最后是std::visit函数,其声明如下:

    template <class Visitor, class... Variants>
    constexpr /*...*/ visit(Visitor&& vis, Variants&&... vars);
    

    其实现的功能是,将vars的可能值传入vis中。

    所以最终便会实现,根据variant中可用参数类型不同,最终生成不一样的字符串,传入字符串流对象convert中。

    到此字典类型核心便的实现了一般,下一步是字符串映射,使用C++标准库中的std::mapstd::unordered_map 便可以实现了。下面是示例代码,可见可以轻松实现Python的字典效果。

    #include <variant>
    #include <iostream>
    #include <sstream>
    #include <string>
    #include <unordered_map>
    
    template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
    template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
    
    int main() {
    
        std::variant<int, long int, char, std::string, float, double> value1;
        std::unordered_map<std::string, std::variant<int, long int, char, std::string, float, double>> dictionary;
    
        dictionary["a"] = "Hello";
        dictionary["b"] = 'I';
        dictionary["c"] = 2;
        dictionary["d"] = 3.14159f;
    
        std::stringstream convert;
    
        for (const auto &item : dictionary) {
            convert.clear();
            convert.str("");
            std::visit(overloaded{
                    [&convert](char value) { convert << value; },
                    [&convert](int value) { convert << value; },
                    [&convert](long int value) { convert << value; },
                    [&convert](float value) { convert << value; },
                    [&convert](double value) { convert << value; },
                    [&convert](const std::string &value) { convert << value; },
            }, item.second);
            std::cout << item.first << ' ' << convert.str() << '
    ';
        }
    }
    

    打印信息如下:

    d 3.14159
    c 2
    a Hello
    b I
    
    任世事无常,勿忘初心
  • 相关阅读:
    API协议
    执行聚合
    执行过滤
    执行查询
    介绍查询语言
    探索你的数据
    探索你的集群(翻译)
    es6.4基本概念(中文翻译)
    Python3.7.4安装
    elasticsearch常用请求
  • 原文地址:https://www.cnblogs.com/FlameBlog/p/14714767.html
Copyright © 2011-2022 走看看