C++17尝鲜:变长 using 声明
using 声明
先来看 using 声明在类中的应用:
代码1
#include <iostream>
using namespace std;
struct A {
void f(int) {cout << "A::f(int)" << endl;}
};
struct S : A {
};
int main()
{
S s;
s.f(1); // A::f(int)
}
- 类 S 继承了类 A 的成员函数 f,所以类 S 的实例 s 调用 f 输出为 A::f
代码2
#include <iostream>
using namespace std;
struct A {
void f(int) {cout << "A::f(int)" << endl;}
};
struct S : A {
void f(double) {cout << "S::f(double)" << endl;}
};
int main()
{
S s;
s.f(1); // S::f(double)
}
- 类 S 继承了类 A 的成员函数 f,同时类 S 也定义了成员函数 f
- 类 S 的成员函数 f 遮蔽了基类中的同名成员函数,所以 S 的实例 s 调用 f 输出为 S::f
代码3
#include <iostream>
using namespace std;
struct A {
void f(int) {cout << "A::f(int)" << endl;}
};
struct S : A {
using A::f;
void f(double) {cout << "S::f(double)" << endl;}
};
int main()
{
S s;
s.f(1); // A::f(int)
s.f(2.5); // S::f(double)
}
- 类 S 继承了类 A 的成员函数 f,同时类 S 也定义了成员函数 f
- 类 S 通过 using 声明将基类 A 的成员函数 f 引入自己的作用域。类 S 的成员函数 f 与基类 A 中的同名成员函数形成重载关系。
- 参数为整型时,根据重载决策 S 的实例 s 调用 f 输出为 A::f
- 参数为浮点型时,根据重载决策 S 的实例 s 调用 f 输出为 S::f
代码4
#include <iostream>
using namespace std;
struct A {
void f(int) {cout << "A::f(int)" << endl;}
};
struct B {
void f(double) {cout << "B::f(double)" << endl;}
};
struct S : A, B {
};
int main()
{
S s;
s.f(1); // compile error
s.f(2.5); // compile error
}
- 类 S 同时继承了类 A 和类 B 的成员函数 f,两者形成竞争关系。
- 编译器不能判断 S 的实例 s 所调用的成员函数 f 来自类 A 还是类 B,故编译出错。
代码5
#include <iostream>
using namespace std;
struct A {
void f(int) {cout << "A::f(int)" << endl;}
};
struct B {
void f(double) {cout << "B::f(double)" << endl;}
};
struct S : A, B {
using A::f;
using B::f;
};
int main()
{
S s;
s.f(1); // A::f(int)
s.f(2.5); // B::f(double)
}
- 类 S 同时继承了类 A 和类 B 的成员函数 f。
- 类 S 通过 using 声明将基类 A 和基类 B 的成员函数 f 都引入自己的作用域。基类 A 和基类 B 的同名成员函数在类 S 中形成重载关系。
- 参数为整型,根据重载决策 S 的实例 s 调用 f 输出为 A::f
- 参数为浮点型时,根据重载决策 S 的实例 s 调用 f 输出为 B::f
C++17的 using 声明
在 C++17 中多个 using 声明可以通过逗号连接起来,合成一个 using 声明。
代码6
#include <iostream>
using namespace std;
struct A {
void f(int) {cout << "A::f(int)" << endl;}
};
struct B {
void f(double) {cout << "B::f(double)" << endl;}
};
struct S : A, B {
using A::f, B::f; // C++17
};
int main()
{
S s;
s.f(1); // A::f(int)
s.f(2.5); // B::f(double)
}
C++17的变长 using 声明
通过使用加了 ... 的 using 声明,可以将变长模板参数类型中的 using 声明转化为由多个用逗号合成的变长 using 声明。
#include <iostream>
#include <string>
using namespace std;
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main()
{
overloaded s{
[](int){cout << "int" << endl;},
[](double){cout << "double" << endl;},
[](string){cout << "string" << endl;},
};
s(1); // int
s(1.); // double
s("1"); // string
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
这是一个类模板的声明。template<class... Ts>:overloaded 类的模板参数为可变长的参数包 Ts。
假设 Ts 包含 T1, T2, ... , TN,那么这一句声明可以展开为:template<class T1, class T2, ..., class TN>struct overloaded : Ts...:overloaded 类的基类为参数包 Ts 内所有的参数类型。
假设 Ts 包含 T1, T2, ... , TN,那么这一句声明可以展开为:struct overloaded : T1, T2, ..., TNusing Ts::operator()...;:这是一个变长 using 声明。
假设 Ts 包含 T1, T2, ... , TN,那么这一句声明可以展开为:using T1::operator(), T1::operator(), ..., TN::operator();
也就是说,overloaded 类的基类即参数包 Ts 内所有的参数类型的函数调用操作符均被 overloaded 类引入了自己的作用域。template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
这是一个自动推断向导,用于帮助编译器根据 overloaded 构造器参数的类型来推导 overloaded 的模板参数类型。
这个自动推断向导告诉编译器,如果 overloaded 构造器所有参数的类型的集合为Ts,那么 overloaded 的模板参数类型就是 Ts 所包含的所有类型。
也就是说如果表达式 a1, a2, ..., an 的类型分别为 T1, T2, ..., TN,
那么构造器表达式overloaded {a1, a2, ..., an}的类型就是overloaded<T1, T2, ..., TN>。
*overloaded s{
[](int){cout << "int" << endl;},
[](double){cout << "double" << endl;},
[](string){cout << "string" << endl;},
};
overloaded 类的实例 s 的构造器包含3个lambda参数,也可以看作3个各自包含一个 operator() 的函数对象。
根据 overloaded 类的定义,s 对象将继承这3个lambda(函数对象)的 operator() ,也就是说这3个lambda的 operator() 即函数体在 s 对象内部形成重载关系。
根据 overloaded 类的自动推断向导,s 对象的类型为overloaded<T1, T2, T3>,其中T1, T2, T3为3个lambda参数的类型。- 通过利用 C++17 的新特性变长的 using 声明以及自动推断向导,overloaded类的实例可以简洁并且巧妙地将多个lambda合成一个大的具有多个相互重载的 operator() 的函数对象。
- overloaded 这个类模板如此有用,实现机制又如此精妙,实在是应该早日纳入标准库中。
C++17尝鲜:变长 using 声明的更多相关文章
- C++17尝鲜
https://cloud.tencent.com/developer/article/1351910 [译]C++17,optional, any, 和 variant 的更多细节 用户261520 ...
- C++17尝鲜:variant
variant variant 是 C++17 所提供的变体类型.variant<X, Y, Z> 是可存放 X, Y, Z 这三种类型数据的变体类型. 与C语言中传统的 union 类型 ...
- C++17尝鲜:结构化绑定声明(Structured Binding Declaration)
结构化绑定声明 结构化绑定声明,是指在一次声明中同时引入多个变量,同时绑定初始化表达式的各个子对象的语法形式. 结构化绑定声明使用auto来声明多个变量,所有变量都必须用中括号括起来. cv-auto ...
- C++17尝鲜:在 if 和 switch 语句中进行初始化
初始化语句 在C++17中,类似于 for 语句,在 if 和 switch 语句的判断条件之前也能加上初始化语句,语法形式如下: if (初始化语句; 条件) 语句 else 语句 switch ( ...
- C++17尝鲜:编译期 if 语句
Constexpr If(编译期 if 语句) 以 if constexpr 打头的 if 语句被称为 Constexpr If. Constexpr If 是C++17所引入的新的语法特性.它为C+ ...
- C++17尝鲜:string_view
string_view string_view 是C++17所提供的用于处理只读字符串的轻量对象.这里后缀 view 的意思是只读的视图. 通过调用 string_view 构造器可将字符串转换为 s ...
- C++17尝鲜:类模板中的模板参数自动推导
模板参数自动推导 在C++17之前,类模板构造器的模板参数是不能像函数模板的模板参数那样被自动推导的,比如我们无法写 std::pair a{1, "a"s}; // C++17 ...
- PL/SQL — 变长数组
PL/SQL变长数组是PL/SQL集合数据类型中的一种,其使用方法与PL/SQL嵌套表大同小异,唯一的区别则是变长数组的元素的最大个数是有限制的.也即是说变长数组的下标固定下限等于1,上限可以扩展.下 ...
- C99新增内容之变长数组(VLA)
我们在使用多维数组是有一点,任何情况下只能省略第一维的长度.比如在函数中要传一个数组时,数组的行可以在函数调用时传递,当属数组的列却只能在能被预置在函数内部.看下面一个例子: #define COLS ...
随机推荐
- 去掉user agent stylesheet 浏览器默认样式 [ 2.0 版本 ]
今天在写一个网页的时候发现一个问题,我的table的样式很奇怪,也没有设置什么样式,跟其他的页面不一样,打开开发者工具一看,发现有这么点样式: 其中右上角:user agent stylesheet ...
- tpadmin导入数据库问题
tpadmin导入数据库后,修改表名tp_web_log_all时报1168错误 原因:该为联合表,原始sql语句中的联合表tp_web_log_001未改变表名,必须修改后用sql语句添加该表
- 倒数第N个字符串
给定一个完全由小写英文字母组成的字符串等差递增序列,该序列中的每个字符串的长度固定为 L,从 L 个 a 开始,以 1 为步长递增.例如当 L 为 3 时,序列为 { aaa, aab, aac, . ...
- 用node.js和webpack做前后端分离的总结
1.webpack打包的特点 (打包文件到指定地点,修改原文件里的引用路径为打包的地点) 涉及output的path/public path/dev-server里的public path等概念 we ...
- vue elment-ui 样式替换 input select
# 有时候经常需要替换element-ui的样式 第一种方法: 直接修改源码,样式路径如下 直接修改idnex.css即可. 第二种方法: 直接在当前页面修改,替换掉原来的样式. <style ...
- [SDOI2016]生成魔咒(后缀自动机)
/* 水题, 根据性质做就行, nq不会对答案产生贡献, 那么只算p的贡献就好了 */ #include<cstdio> #include<algorithm> #includ ...
- windows下解决python输出utf-8中文
class UnicodeStreamFilter: def __init__(self, target): self.target = target self.encoding = 'utf-8' ...
- es6(8)--对象
//对象 { //简洁表示法 let o = 1; let k = 2; let es5 = { o:o, k:k }; let es6 = { o, k }; console.log(es5); c ...
- 安全测试2_Web前端知识学习
上次讲到安全的简介,这次就来简单的学习下基本的前端知识(html.js.css(不作讲解),牛逼的请忽略!!! 1.Html简单概述: Html和Html DOM 2.Html字符实体(借用别人的,详 ...
- Object-c基本语法
// // main.m // OCbasic1 // // Created by apple on 14-8-5. // Copyright (c) 2014年 苹果IOS软件开发者. Al ...