当前位置: 首页 > news >正文

为什么一个人做网站有难度长春网站建设案例

为什么一个人做网站有难度,长春网站建设案例,wordpress静态,本地手机网站建设1简介 C17的三剑客分别是std::optional, std::any, std::vairant。今天主要讲std::variant。std::variant的定义如下&#xff1a; template< class... Types > class variant; 类模板 std::variant 表示一个类型安全的联合体&#xff08;以下称“变化体”&#xff09;…

1简介

C++17的三剑客分别是std::optional, std::any, std::vairant。今天主要讲std::variant。std::variant的定义如下:

template< class... Types >
class variant;

类模板 std::variant 表示一个类型安全的联合体(以下称“变化体”)。std::variant 的一个实例在任意时刻要么保有它的一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception);从功能上讲,它就跟union的功能差不多,但却比union更高级;variant主要是为了提供更安全的union。举个例子union里面不能有string这种类型,但std::variant却可以,还可以支持更多复杂类型,如map等

2辅助类

2.1 std::monostate

为了支持第一个类型没有默认构造函数的variant对象,提供了一个特殊的helper类型:std::monostate。类型std::monostate的对象总是具有相同的状态,因此,它们总是相等的。它自己的目的是表示另一种类型,这样variant就没有任何其他类型的值。也就是说,std::monostate可以作为第一种替代类型,使变体类型默认为可构造。
 

std::variant<std::monostate, int> test; // OK
std::cout << "index: " << test.index(); //输出: 0

我们可以简单理解std::monostate是个占位符。

2.2 std::bad_variant_access

 std::bad_variant_access 是下列情形中抛出的异常类型:

  • 以不匹配当前活跃可选项的下标或类型调用 std::get(std::variant)
  • 调用 std::visit 观览因异常无值 (valueless_by_exception) 的 variant

       示例如下:

#include <variant>
#include <iostream>int main()
{std::variant<int, float> v;v = 12;try {std::get<float>(v);}catch(const std::bad_variant_access& e) {std::cout << e.what() << '\n';}
}

可能的输出:

bad_variant_access

2.3 std::variant_size和std::variant_size_v

提供作为编译时常量表达式,对可有 cv 限定的 variant 中可选项数量的访问,示例如下:

#include <any>
#include <cstdio>
#include <variant>static_assert(std::variant_size_v<std::variant<>> == 0);
static_assert(std::variant_size_v<std::variant<int>> == 1);
static_assert(std::variant_size_v<std::variant<int, int>> == 2);
static_assert(std::variant_size_v<std::variant<int, int, int>> == 3);
static_assert(std::variant_size_v<std::variant<int, float, double>> == 3);
static_assert(std::variant_size_v<std::variant<std::monostate, void>> == 2);
static_assert(std::variant_size_v<std::variant<const int, const float>> == 2);
static_assert(std::variant_size_v<std::variant<std::variant<std::any>>> == 1);int main() { std::puts("All static assertions passed."); }

输出:

All static assertions passed.

2.4 std::variant_alternative和std::variant_alternative_t

提供对 variant 的类型编译时下标访问,示例如下:

#include <variant>
#include <iostream>using my_variant = std::variant<int, float>;
static_assert(std::is_same_v<int,   std::variant_alternative_t<0, my_variant>>);
static_assert(std::is_same_v<float, std::variant_alternative_t<1, my_variant>>);
// variant 类型上的 cv 限定传播给提取出的可选项类型。
static_assert(std::is_same_v<const int, std::variant_alternative_t<0, const my_variant>>);int main()
{std::cout << "All static assertions passed\n";
}

输出:

All static assertions passed

3 std::variant的操作

std::variant提供的主要操作有:

操作说明
constructors创建一个variant对象(可能调用底层类型的构造函数)
destructor销毁一个variant对象
emplace<T>()为具有类型T的备选项分配一个新值
emplace<Idx>()为索引Idx的备选项分配一个新值
=分配一个新值
index()返回当前备选项的索引
holds_alternative<T>()返回类型T是否有值
==, !=, <, <=, >, >=比较variant对象
swap()交换两个对象的值
hash<>函数对象类型来计算哈希值
valueless_by_exception()返回该变量是否由于异常而没有值
get<T>()返回备选项类型为T的值或抛出异常(如果没有类型为T的值)
get<Idx>()返回备选项索引为idx的值或抛出异常(如果没有索引为idx的值)
get_if<T>()返回指向类型为T指针或返回nullptr(如果没有类型为T的值)
get_if<Idx>()返回指向索引Idx的指针或nullpt(如果没有索引为idx的值)
visit()为当前备选项执行操作

3.1 定义

直接定义std::variant,如:

std::variant<std::uint32_t, double, std::string, std::int32_t>  t;

可以对 t 赋初值,对于基本类型,它是0、false还是nullptr。如果传递一个值进行初始化,则使用最佳匹配类型,如:

std::variant<std::uint32_t, double, std::string, std::int32_t>  t{ 25 };
cout << t.index(); //输出: 3

要传递多个值进行初始化,必须使用in_place_type或in_place_index标记:

std::variant<std::complex<double>> t1{1.0,564.0}; // ERROR
std::variant<std::complex<double>> t2{std::in_place_type<std::complex<double>>,
322.0, 2323.0};
std::variant<std::complex<double>> t3{std::in_place_index<0>, 35.0, 8.0};

如果初始化过程中出现歧义或匹配问题,可以用in_place_index标签来解决,如:

std::variant<int, int> t1{std::in_place_index<1>, 77}; // init 2nd int
std::variant<int, long> t2{std::in_place_index<1>, 77}; // init long, not int
std::cout << t2.index(); // prints 1

3.2 访问值

std::variant可以通std::get来获取或修改值。

std::variant<std::uint32_t, double, std::string, std::int32_t> var; 
auto x = std::get<double>(var); 
auto y = std::get<4>(var); // compile-time ERROR: no 4th alternative
auto c = std::get<int>(var); try{auto m = std::get<std::string>(var); // throws exception (first int currently set)auto n = std::get<0>(var); // OK, i==0auto o = std::get<1>(var); // throws exception (other int currently set)
}
catch (const std::bad_variant_access& e) { // in case of an invalid accessstd::cout << "Exception: " << e.what() << '\n';
}

std::get_if用来判断某项是否存在

#include <variant>
#include <iostream>int main()
{std::variant<int, float> v{12};if(auto pval = std::get_if<int>(&v))std::cout << "variant value: " << *pval << '\n';   //输出: 12else std::cout << "failed to get value!" << '\n'; 
}

还可以通过std::visit来访问值:

struct stValueVisitor {void operator()(int i) { cout << "int: " << i << '\n'; }void operator()(float f) { cout << "float: " << f << '\n'; }void operator()(const std::string& s) { cout << "str: " << s << '\n'; }
};int main() {std::variant<int, float, string> value = 65.2;std::visit(stValueVisitor{}, value);  // 输出 float: 65.2return 0;}

也可以利用C++17 新增的 overloaded 模板,可以直接生成匿名访问器,简化代码, 下面的代码是等价的: 

int main() {std::variant<int, float, string> t= 56.4;std::visit(overloaded{void operator()(int i) { cout << "int: " << i << '\n'; }void operator()(float f) { cout << "float: " << f << '\n'; }void operator()(const std::string& s) { cout << "str: " << s << '\n'; }},t);}

接下来还有第三种方法来访问std::variant : 

int main()
{std::variant<int, float, string> t = 16.4;std::visit([&](auto &&arg) {using T = std::decay_t<decltype(arg)>; // 类型退化,去掉类型中的const 以及 &if constexpr(std::is_same_v<T,int>) {cout << "int: " << arg << '\n';} else if constexpr(std::is_same_v<T,float>){cout<< "float: "<< arg <<'\n';} else if constexpr(std::is_same_v<T,std::string>){cout<< "str: "<< arg <<'\n';}}, t);
}

这里我们可以看出来第三种写法比第一种的优势在哪里了:编译期推断。
第三种方法由于使用了constexpr 进行 if 分支的判断,因此是在编译期运行,而第一种方法是运行期进行类型判断,效率是不同的。
第二种方法和模板一样,也是编译期推断的,因此效率也是很高的,所以我们应当尽量使用 std::visit 方法来访问variant 变量

另外std::visit 还有一个好处是,它的参数列表是不定长的,我们可以传入多个variant 变量

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

3.3 修改值

用std::get来修改值,如:

std::variant<std::uint32_t, double, std::string, std::int32_t> t; 
std::get<double>(t) = 1.0;
cout << t.index();  //输出: 1
std::get<std::uint32_t>(t) = 34;
cout << t.index();  //输出: 0
std::get<2>(t) = "4343636";
cout << t.index();  //输出:2

也可以用std::get_if来修改值,如:

std::variant<std::uint32_t, double, std::string, std::int32_t> t; 
if (auto p = std::get_if<1>(&t)) { // if second int set*p = 42.2; // modify it
}

4 总结

以上都是我日常工作中对std::variant的用法的总结;做技术,要知其然,更要知其所以然,后面我将从std::varant的源码实现上继续分析它的原理,敬请期待。。。

参考

std::visit

std::variant

http://www.yayakq.cn/news/668716/

相关文章:

  • 网站建设技术方案模板海淀做网站设计的公司
  • 能不能不用虚拟主机建设网站wordpress小工具里的用户中心
  • 网站怎么优化排名wordpress如何添加注册登录界面
  • 建设通网站联系电话怎么做网络营销平台
  • 各类网站建设临夏网站建设
  • 企业品牌网站建设注意事项做seo推广一年大概的费用
  • 重庆建设工程信息网官网查询系统网址企业网站seo贵不贵
  • 企业网站后台管理系统模板下载如何做招聘网站效果评估
  • 织梦网站栏目添加搭建网页聊天室
  • 安庆做网站企业济南网站建设要多少钱
  • 中科院网站建设wordpress关注微信登陆
  • 导购网站一站式建站h5免费制作平台火蚁
  • 专业网站设计定制成都有哪些设计公司
  • 个人网站建设推广服务最近10个新闻
  • 台州网站建设多少钱软件维护有哪些内容
  • 如何做网上销售网站wordpress主题更换头部媒体
  • 长春网站建设新格宁波seo关键词费用
  • 网站建设价格是多少wordpress两个主题混合
  • 有空间有域名怎么做网站网站开发技术入股协议
  • 用 php网站建设打出一首古诗浏览器什么网站都能打开的
  • wordpress手机分享插件下载东莞关键词优化软件
  • 网站建设询价邀请函制作人
  • 苏州做企业网站有哪些有什么软件做短视频网站
  • s001网站建设WordPress设置腾讯企业邮箱
  • 物流好的网站模板下载网站建设网页怎么排列顺序
  • wordpress关停网站怎么免费做网站
  • 商城网站seo网站建设的目的及功能
  • 有几家公司如何建设网站网站建设忄金手指快速
  • 布谷海南网站建设广州seo推广
  • 网站交接需要哪些自己开发一个app需要什么