详解 c++17 重载类 overload的每一条语句,附实例.
author: hjjdebug
date: 2025年 05月 09日 星期五 16:21:03 CST
description: 详解 c++17 重载类 overload的每一条语句
文章目录
- 1. template 模板类.
- 2. class... Ts 是什么意思?
- 3. template<class... Ts> 是什么意思?
- 4. overload 是什么?
- 5. Ts... 是什么?
- 6. 小结
- 7. using Ts::operator()... 是什么意思?
- 8. overload(Ts...)-> overload<Ts...>
- 9 附上我的研究代码.
- 10. 这个重载类有什么用呢?
我看到了几行奇怪的代码,我想理解它的意思.
template<class... Ts>
struct overload : Ts... {
using Ts::operator()...;
};template<class... Ts>
overload(Ts...)-> AAA<Ts...>;
1. template 模板类.
template 是一个c++关键字,代表模板类.
模板类在编译时是不生成代码的, 当实例化时,给了具体的类型,才生成对应的代码.
2. class… Ts 是什么意思?
如果没有… 而是 class Ts, 它的含义是类型名称 是Ts, 这也是基本使用方法.
其中Ts 是描述符.
而这里 class… Ts, 则表示Ts 代表了很多类型.
Ts 是一个描述符,也可以替换它为你喜欢的名称,它本来是Types简写,用Ts代替已经很简洁了.
3. template<class… Ts> 是什么意思?
是定义一个模板类,它的参数类型有很多种, Ts是型参的名称
4. overload 是什么?
overload 是一个类型的名称, 它是一个普通的描述符
我把overload改成AAA, 编译是照样可以通过的,只不过模板类型的名称就叫AAA了.
5. Ts… 是什么?
Ts… 代表的是多种类型的意思,Ts是型参的名称
这些都是跟编译器的约定,被改编之后的gcc,是理解你的这种用法的.
6. 小结
template<class… Ts>
struct AAA : Ts… {
};
定义了一个模板类型,其名称叫AAA, 该模板输入参数类型很多.
该AAA类型公有继承了它的子类型 各个Types, 因而它可以使用各个子Types 中定义的函数.
struct 的继承默认是公有继承 public 类型, 当然你也可以显示声明为public.
7. using Ts::operator()… 是什么意思?
此处的 using 语句,表明它要使用各基类Ts的() 操作符,使基类的函数操作符为可见.
这样就可以用小括号包住子对象.
如果你注释掉该语句,则s(1),s(“1”),s(st)等编译时都会出现错误,编译器不知道你用小括号包住子变量是什么意思.
其实我们括注子变量当然是构造对象时传递的一个参数的意思,
不知道模板类为什么不把它做为一种默认的行为?
而必需要我们显示的像上面那样来说明.
8. overload(Ts…)-> overload<Ts…>
-> 代表推导的意思.
它告诉gcc, 当你碰到overload(Ts…)的使用方法时,就去实例化一个overload<Ts…>类型
这里我也有点不清楚,这难道不应该是默认的行为吗? 为什么还要我们显示说明呢?
也就是说按我的意思,只要用了…多类型,就不用声明using,及模板类型推导语句,岂不是更简洁!
9 附上我的研究代码.
cat main.cpp
#include <iostream>
#include <string>
using namespace std;
//class... Ts,说明Ts可代表多种类型
template<class... Ts>
//AAA 类继承了Ts类, Ts...表示多种类型
struct AAA : Ts... {// using 关键字,引入基类Ts::operator(),使其到父类作用域中//此处using 的作用是防止基类函数被隐藏//基类函数被隐藏是说当基类中有一个函数,派生类中有同名函数,则基类函数被隐藏.//有多个operator(), 将来会调用那一个? 这是编译器的函数重载功能.using Ts::operator()...; // 注释掉该语句, s(1)调用会出现error: request for member ‘operator()’ is ambiguous
};//class 说明是一种类型,...是多种类型,Ts是一个标识符,代表类型types
template<class... Ts>
//Ts... Ts,任意类型...任意个数
//推导规则,当调用AAA(Ts...),推导出类型AAA<Ts...>
//注释掉该语句,当声明AAA变量s 时,
//会有错误 cannot deduce template arguments of ‘AAA<Ts>’, as it has no viable deduction guides
AAA(Ts...)-> AAA<Ts...>;
//这是给编译器沟通的语言,通过构造函数的参数类型,推导出模板的类型
//所以这种写法几乎构成了固定的搭配typedef struct _Test
{int a;int b;//这里的operator() 给模板类中的using Ts::operator 没有任何关联void operator()(struct _Test st){cout<<"struct _Test"<<st.a<<endl;}
}Test;
int main() {//定义一个AAA类型的变量s,其有有2种构造函数,当参数类型为int时,为一种,当参数类型为string时,为另一种//AAA 实际的功能是一个重载类型AAA s{ //多个lamda 表达式[](int){ cout << "int" << endl; }, [](string){ cout << "string" << endl;},[](Test){ cout << "Test struct"<<endl;}};Test st;s(1); // int 参数,与AAA:: using Ts::operator() 有关联,变量函数式.s("1"); // string参数,与AAA:: using Ts::operator() 有关联s(st); //自定义的struct _Test 类型, 也与AAA:: using Ts:operator()有关联cout<<"sizeof(AAA):"<<sizeof(s)<<endl; //AAA类型大小是一个象征性大小1,它是不占用内存的.
}
代码的执行结果:
$ ./overload
int
string
Test struct
sizeof(AAA):1
10. 这个重载类有什么用呢?
这个重载类,它不是装东西的,因为它实例的大小只是象征性大小1.
但它能够根据不同的参数类型,调用不同的构造函数.
这是跟编译器的约定.
跟编译器约好了模板,约好了…,约好了由参数类型导出模板类型(需显式说明),约好了函数式子类型(需显式说明)
就这么点意思,搞的好复杂.有这个必要吗?语言的复杂性正在掩盖一些本质的东西.
使用起来似乎能简洁一点,但理解起来复杂了一点.