由于在看QT5.15.2
中的connect
方法中的typedef QtPrivate::FunctionPointer
使用以及,QtPrivate::FunctionPointer
的声明。而产生的疑问,因此有了这篇内容。QtPrivate::FunctionPointer
的声明如下:
// 第一个
template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
// 第二个
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)>
{
typedef Obj Object;
typedef List<Args...> Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Args...);
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
template <typename SignalArgs, typename R>
static void call(Function f, Obj *o, void **arg) {
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
}
};
QtPrivate::FunctionPointer
的声明总共有七个,这里不再一一粘贴,看到这里不知诸位会不会产生以下几个疑问:
QtPrivate::FunctionPointer
后面尖括号中的内容是什么QtPrivate::FunctionPointer
与第一个有什么关系,我们都知道typedef QtPrivate::FunctionPointer SignalType;
会最终匹配到那个类型我这里使用的环境是VS2019
编写的代码, C++ 14
的编译标准
声明一个结构体模板,声明形式如下
template <typename A> struct Test<A> {};
这种写法会产生如下错误
从这个错误提示中我们可以得到信息如下:
主模板
(那有主模板是不是就由次模板呢?这里的次模板是我自己定义的,因为在网上没有查找到相关资料,若有知道官方资料地址,请评论区留言感谢!!!)模板参数列表
(模板参数列表起到的具体作用是什么?)主模板与次模板一起声明
次模板声明的官方标准暂未找到~~~
这里的声明仿照了QT
的源码
template<class Obj> struct FunctionPointer {};
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret(Obj::*) (Args...)>
{
typedef Obj Object;
enum { ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true };
typedef List<Args...> Arguments;
};
接下来看FunctionPointer
的用已经VS
的智能提示
看到这个智能提示诸位是否觉得有点像重载
的提示呢?(这也是为什么文章标题是类模板的重载)。
看到第一个提示大家应该很熟悉,就是任意类型。
那第二个是什么呢?整体看起来有么有感觉它很想函数指针类型
呢? 没错它就是一个函数指针类型
,但确实一个类的成员函数指针类型
,而(Args...)
则表示该函数的参数。
用其声明一个变量如下:
/*
template struct FunctionPointer
声明的变量与结构体模板声明中各个类型的对象关系:
1. Obj:会被推导为MyClass
2. Ret:会被推导为void
3. Args:则会被推导为0个类型
这里回答 "模板参数列表起到的具体作用是什么?" 这个问题,模板参数列表起到作用是指定这个模板类型接受的参数类型
*/
FunctionPointer<void(MyClass::*)()> fpTest;
到这里我想最初的那三个问题,小伙伴们应该已经知道答案了吧。问题如下:
QtPrivate::FunctionPointer
后面尖括号中的内容是什么QtPrivate::FunctionPointer
与第一个有什么关系,我们都知道typedef QtPrivate::FunctionPointer SignalType;
会最终匹配到那个类型根据typedef List
衍生的验证,List
模板类型的声明如下:
template <typename...> struct List { int primary; };
template <typename Head, typename... Tail> struct List<Head, Tail...> { typedef Head Car; typedef List<Tail...> Cdr; int ts; };
List
的使用及智能提示
在第二个的智能提示中多个,
且前面是空的,这个会有什么影响呢?看下面List
的使用:
// 可以看到,由于设置了两个类型,会被匹配到List的次模板(重载模板)
List<int, string> list1;
list1.ts = 0;
// 一个类型同样会被匹配到次模板
List<int> list2;
list2.ts = 0;
// 不设置类型的时候,被匹配到了主模板
List<> list3;
list3.primary = 0;
// 多于两个类型的同样会被匹配到次模板
List<int, string,int> list4;
list4.ts = 0;
目前看下来智能提示中多个,
且前面是空的,好像对传入类型什么的并没有影响,这个应该是个标记(个人猜测),这个,
目前测试看仅在主模板中存在可变模板参数时才会有。
// 主模板包含可变参数类型时,次模板才可以调整模板参数类型的个数,但次模板不可与主模板参数类型一致
template <typename A, typename...> struct List2 { int primary; };
template <typename A, typename B,typename... Tail> struct List2<A, B,Tail...> { int abtail; };
template <typename A> struct List2<A> { int A; };
template <typename A, typename B> struct List2<A,B> { int AB; };
template <typename A, typename B, typename C> struct List2<A,B,C> { int ABC; };
// 次模板与主模板参数类型一致 error
// template struct List2 { int abtail; };
// 主模板不包含可变参数类型时,次模板可以包含可变参数类型
template <typename A> struct Test { int primary; };
template <class A, typename... B> struct Test<A(*) (B...)> { int testAmultiB; };
/*
* 将可变模板参数改掉后
* 1. 若 template struct Test { int testAmultiB; }; 存在则匹配此模板
* 2. 若其不存在则匹配到主模板
*/
//template struct Test { int testAB; };
/*
* 以下两种写法都会被认为类模板参数太多,第一种是可能是因为主模板不包含可变参数,若次模板包含可变参数时
* 可变参数需要放到可以被解释的参数中,如函数的形参
*
* 第二种暂不清楚
*/
//template struct Test { int testAmultiB; };
//template struct Test { int testAB; };
特化写法如下:
template <typename A, typename B> struct templateSpecialization {};
template <typename A> struct templateSpecialization<A, int> {};
template <> struct templateSpecialization<char, int> {};
// templateStruct.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
using namespace std;
class MyClass
{
public:
MyClass() = default;
~MyClass() = default;
void test(int,int) { return; }
};
template <typename A, typename B> struct templateSpecialization {};
template <typename A> struct templateSpecialization<A, int> {};
template <> struct templateSpecialization<char, int> {};
template <typename...> struct List { int primary; };
template <typename Head, typename... Tail> struct List<Head, Tail...> { typedef Head Car; typedef List<Tail...> Cdr; int ts; };
// 主模板包含可变参数类型时,次模板才可以调整模板参数类型的个数,但次模板不可与主模板参数类型一致
template <typename A, typename...> struct List2 { int primary; };
template <typename A, typename B,typename... Tail> struct List2<A, B,Tail...> { int abtail; };
template <typename A> struct List2<A> { int A; };
template <typename A, typename B> struct List2<A,B> { int AB; };
template <typename A, typename B, typename C> struct List2<A,B,C> { int ABC; };
// 次模板与主模板参数类型一致 error
// template struct List2 { int abtail; };
// 主模板不包含可变参数类型时,次模板可以包含可变参数类型
template <typename A> struct Test { int primary; };
template <class A, typename... B> struct Test<A(*) (B...)> { int testAmultiB; };
/*
* 将可变模板参数改掉后
* 1. 若 template struct Test { int testAmultiB; }; 存在则匹配此模板
* 2. 若其不存在则匹配到主模板
*/
//template struct Test { int testAB; };
/*
* 以下两种写法都会被认为类模板参数太多,第一种是可能是因为主模板不包含可变参数,若次模板包含可变参数时
* 可变参数需要放到可以被解释的参数中,如函数的形参
*
* 第二种暂不清楚
*/
//template struct Test { int testAmultiB; };
//template struct Test { int testAB; };
template<class Obj> struct FunctionPointer {};
template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret(Obj::*) (Args...)>
{
typedef Obj Object;
enum { ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true };
typedef List<Args...> Arguments;
};
template <typename Func1, typename Func2>
static inline void connect(const typename FunctionPointer<Func1>::Object* sender, Func1 signal,
const typename FunctionPointer<Func2>::Object* receiver, Func2 slot)
{
const type_info& nInfo = typeid(Func1);
cout << nInfo.name() << " | " << nInfo.raw_name() << " | " << nInfo.hash_code() << endl;
const type_info& inInfo = typeid(FunctionPointer<Func1>::Arguments::Car);
cout << inInfo.name() << " | " << inInfo.raw_name() << " | " << inInfo.hash_code() << endl;
cout << FunctionPointer<Func1>::ArgumentCount << endl;
}
int main()
{
typedef void (*ptr)();
Test<ptr> test1;
test1.testAmultiB;
FunctionPointer<void(MyClass::*)()> fpTest;
List<int,string> list1;
list1.ts = 0;
List<int> list2;
list2.ts = 0;
List<> list3;
list3.primary = 0;
List<int, string,int> list4;
list4.ts = 0;
List2<int> list21;
list21.A = 0;
List2<int,int> list22;
list22.AB = 0;
List2<int,int,int> list23;
list23.ABC;
MyClass a;
connect(&a, &MyClass::test, &a, &MyClass::test);
}