如何实现CC++中可变参数模版与函数指针的融合应用?

2026-05-22 07:353阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1999个文字,预计阅读时间需要8分钟。

如何实现C/C++中可变参数模版与函数指针的融合应用?

目录

1.说明

2.模板类传入固定参数的C函数指针

3.模板类传入固定参数的C++函数指针

3.1. 用函数对象代替函数指针存储

4.模板类传入不固定参数的C函数指针

5.模板类传入不固定参数的函数指针

目录
  • 1、说明
  • 2、模板类传入固定参数的C函数指针
  • 3、模板类传入固定参数的C++函数指针
    • 3.1、用函数对象替代函数指针存储
  • 4、模板类传入不定参数的C函数指针
  • 5、模板类传入不定参数的C++成员函数指针

最近因为想自己写一个信号槽,看到了一些开源代码,才发现,自己对模版的理解还是太浅了,理解了C++的模版才算真正入门了C++

1、说明

本文只针对技术提炼说明,不对使用场景做介绍。内容的理解需要在理解模板类(包括模板类的使用以及隐式/显式实例化)和C/C++函数指针以及stl函数对象的基础上

下面从以下几点讲解:

  1. 模板类传入C函数指针,函数参数固定;
  2. 模板类传入C++函数指针,函数参数固定;
  3. 模板类传入C函数指针,函数参数不固定;
  4. 模板类传入C++函数指针,函数参数不固定
2、模板类传入固定参数的C函数指针

先看一组示例:

template<typename T> class Test; template<typename F> class Test<F(int)> { public: typedef F(*Callback)(int); explicit Test(Callback func) : callback(func) {} void exec() { callback(999); } private: Callback callback; };

需要执行的函数:

int TestFunction(int value) { cout << value + 2 << endl; return value; }

调用示例:

int main() { Test<int(int)> test(TestFunction); test.exec(); return 0; }

执行结果:

1001

代码讲解:

template<typename F> class Test<F(int)> {}

理解一下上面这段代码做了什么,首先,这 是一个模板类的,并且它也是 模板类的显示实例化,既然是显示实例化,那么就需要模板类的声明,这就是下面第一二行代码的存在意义

template<typename T> class Test;//模板类声明

这段可以这样理解,这里是先声明一个模板类 Test,它需要传入一个类型T;然后再显示实例化,显示实例化之后的类还是一个模板类,实例化的类需要传入的是一个函数指针(该函数指针就是第一个Test的T的显示实例化类型,即第一个Test的类型T被显示实例化为函数指针),该函数指针的返回值是类型F,参数有且只有一个int型,函数指针的声明如下:

如何实现C/C++中可变参数模版与函数指针的融合应用?

typedef F(*Callback)(int);

所以,我们在使用的时候,需要指定,我们使用的是显示实例化的Test(这个Test类还是一个模板类,但是不同与前一个模板类Test),所以需要明确指定类型,如下所示:

Test<int(int)> test(TestFunction);

这行代码告诉编译器,我们使用的是显示实例化之后的模板类,另外需要再隐式实例化该模板类:

template<typename F> class Test<F(int)>//隐式实例化,F类型为int {}

然后使用构造函数,传入C函数指针 TestFunction,执行 exec() 方法的时候,则执行传进入的C函数

3、模板类传入固定参数的C++函数指针

示例代码如下:

template<typename T> class Test; template<typename F> class Test<F(int)> { public: typedef F(TestClass::*TestCallback)(int); explicit Test(TestClass *ptr, TestCallback func) : ptr(ptr), testCallback(func) {} void exec() { (*ptr.*testCallback)(777); } private: TestCallback testCallback; TestClass *ptr; };

需要执行的C++类函数

class TestClass { public: int TestFunction(int value) { cout << value + 2 << endl; return value; } };

调用方:

int main() { TestClass testClass; Test<int(int)> test(&testClass, &TestClass::TestFunction); test.exec(); return 0; }

执行结果:

779

代码说明:

模板类Test大致同第二节,只是这里的函数指针定义变成了类成员

typedef F(TestClass::*TestCallback)(int);

正因为如此,调用处不能只传一个函数指针,还需要类对象,所以构造函数需要两个变量,如下:

explicit Test(TestClass *ptr, TestCallback func) : ptr(ptr), testCallback(func) {}

执行函数这段使用类函数指针调用即可(看不懂的回去复习函数指针一文)

void exec() { (*ptr.*testCallback)(777); } 3.1、用函数对象替代函数指针存储

上面代码分别出处了类对象和类函数指针,C++11中也可组合成函数对象,可以使得代码更直观,代码如下:

template<typename T> class Test; template<typename F> class Test<F(int)> { public: typedef F(TestClass::*TestCallback)(int); explicit Test(TestClass *ptr, TestCallback func) { testCall = std::bind(func, ptr, std::placeholders::_1); } void exec() { testCall(888); } private: std::function<F(int)> testCall; };

代码说明:

这段代码的修改部分就是在构造函数中,不再存储函数指针和函数对象,而是利用C++11的std::bind组合成函数对象,代码的可读性更好,当然C函数也可以使用函数对象,这里不细说

4、模板类传入不定参数的C函数指针

第二节示例代码中传入的C函数是固定参数的函数,如果我们想灵活一点,传入不定参数,则需要做一些改动,示例代码如下:

template<typename T> class Test; template<typename F, typename... Args> class Test<F(Args...)> { public: typedef F(*Callback)(Args... args); explicit Test(Callback callback) : callback(callback) {} void exec() { callback(11, 22, 33); } private: Callback callback; };

需要执行的C++普通函数

template<typename... Args> int TestFunction(Args... args) { std::list<int> arg_list = std::initializer_list<int>{args...}; while (!arg_list.empty()) { cout << arg_list.front() << endl; arg_list.pop_front(); } return 0; }

调用处:

Test<int(int, int, int)> test(TestFunction); test.exec();

运行结果:

11 22 33

代码说明:

模板类Test需要做一些改动,指定参数类型即可

template<typename F, typename... Args> class Test<F(Args...)>

调用出需要指定不定参数的类型和数量

Test<int(int, int, int)> test(TestFunction);//实例化模板 5、模板类传入不定参数的C++成员函数指针

和之前的demo不同,这里将上文的 TestClass 模板类型

template<typename M, typename T> class Test; template<typename M, typename F, typename... Args> class Test<M, F(Args...)> { public: typedef F(M::*TestCallback)(Args...); explicit Test(M *ptr, TestCallback func) : ptr(ptr), testCallback(func) { } void exec() { (*ptr.*testCallback)(11, 22, 33); } private: TestCallback testCallback; M *ptr; };

需要执行的类方法

template<typename ...Args> class TestClass { public: int TestFunction(Args... args) { std::list<int> arg_list = std::initializer_list<int>{args...}; while (!arg_list.empty()) { cout << arg_list.front() << endl; arg_list.pop_front(); } return 0; } };

调用处

template<typename... Args> void func() { using TC = TestClass<Args...>; TC testClass; Test<TC, int(Args...)> test(&testClass, &TC::TestFunction); test.exec(); } int main() { func<int, int, int>();//实例化 return 0; }

标签:结合

本文共计1999个文字,预计阅读时间需要8分钟。

如何实现C/C++中可变参数模版与函数指针的融合应用?

目录

1.说明

2.模板类传入固定参数的C函数指针

3.模板类传入固定参数的C++函数指针

3.1. 用函数对象代替函数指针存储

4.模板类传入不固定参数的C函数指针

5.模板类传入不固定参数的函数指针

目录
  • 1、说明
  • 2、模板类传入固定参数的C函数指针
  • 3、模板类传入固定参数的C++函数指针
    • 3.1、用函数对象替代函数指针存储
  • 4、模板类传入不定参数的C函数指针
  • 5、模板类传入不定参数的C++成员函数指针

最近因为想自己写一个信号槽,看到了一些开源代码,才发现,自己对模版的理解还是太浅了,理解了C++的模版才算真正入门了C++

1、说明

本文只针对技术提炼说明,不对使用场景做介绍。内容的理解需要在理解模板类(包括模板类的使用以及隐式/显式实例化)和C/C++函数指针以及stl函数对象的基础上

下面从以下几点讲解:

  1. 模板类传入C函数指针,函数参数固定;
  2. 模板类传入C++函数指针,函数参数固定;
  3. 模板类传入C函数指针,函数参数不固定;
  4. 模板类传入C++函数指针,函数参数不固定
2、模板类传入固定参数的C函数指针

先看一组示例:

template<typename T> class Test; template<typename F> class Test<F(int)> { public: typedef F(*Callback)(int); explicit Test(Callback func) : callback(func) {} void exec() { callback(999); } private: Callback callback; };

需要执行的函数:

int TestFunction(int value) { cout << value + 2 << endl; return value; }

调用示例:

int main() { Test<int(int)> test(TestFunction); test.exec(); return 0; }

执行结果:

1001

代码讲解:

template<typename F> class Test<F(int)> {}

理解一下上面这段代码做了什么,首先,这 是一个模板类的,并且它也是 模板类的显示实例化,既然是显示实例化,那么就需要模板类的声明,这就是下面第一二行代码的存在意义

template<typename T> class Test;//模板类声明

这段可以这样理解,这里是先声明一个模板类 Test,它需要传入一个类型T;然后再显示实例化,显示实例化之后的类还是一个模板类,实例化的类需要传入的是一个函数指针(该函数指针就是第一个Test的T的显示实例化类型,即第一个Test的类型T被显示实例化为函数指针),该函数指针的返回值是类型F,参数有且只有一个int型,函数指针的声明如下:

如何实现C/C++中可变参数模版与函数指针的融合应用?

typedef F(*Callback)(int);

所以,我们在使用的时候,需要指定,我们使用的是显示实例化的Test(这个Test类还是一个模板类,但是不同与前一个模板类Test),所以需要明确指定类型,如下所示:

Test<int(int)> test(TestFunction);

这行代码告诉编译器,我们使用的是显示实例化之后的模板类,另外需要再隐式实例化该模板类:

template<typename F> class Test<F(int)>//隐式实例化,F类型为int {}

然后使用构造函数,传入C函数指针 TestFunction,执行 exec() 方法的时候,则执行传进入的C函数

3、模板类传入固定参数的C++函数指针

示例代码如下:

template<typename T> class Test; template<typename F> class Test<F(int)> { public: typedef F(TestClass::*TestCallback)(int); explicit Test(TestClass *ptr, TestCallback func) : ptr(ptr), testCallback(func) {} void exec() { (*ptr.*testCallback)(777); } private: TestCallback testCallback; TestClass *ptr; };

需要执行的C++类函数

class TestClass { public: int TestFunction(int value) { cout << value + 2 << endl; return value; } };

调用方:

int main() { TestClass testClass; Test<int(int)> test(&testClass, &TestClass::TestFunction); test.exec(); return 0; }

执行结果:

779

代码说明:

模板类Test大致同第二节,只是这里的函数指针定义变成了类成员

typedef F(TestClass::*TestCallback)(int);

正因为如此,调用处不能只传一个函数指针,还需要类对象,所以构造函数需要两个变量,如下:

explicit Test(TestClass *ptr, TestCallback func) : ptr(ptr), testCallback(func) {}

执行函数这段使用类函数指针调用即可(看不懂的回去复习函数指针一文)

void exec() { (*ptr.*testCallback)(777); } 3.1、用函数对象替代函数指针存储

上面代码分别出处了类对象和类函数指针,C++11中也可组合成函数对象,可以使得代码更直观,代码如下:

template<typename T> class Test; template<typename F> class Test<F(int)> { public: typedef F(TestClass::*TestCallback)(int); explicit Test(TestClass *ptr, TestCallback func) { testCall = std::bind(func, ptr, std::placeholders::_1); } void exec() { testCall(888); } private: std::function<F(int)> testCall; };

代码说明:

这段代码的修改部分就是在构造函数中,不再存储函数指针和函数对象,而是利用C++11的std::bind组合成函数对象,代码的可读性更好,当然C函数也可以使用函数对象,这里不细说

4、模板类传入不定参数的C函数指针

第二节示例代码中传入的C函数是固定参数的函数,如果我们想灵活一点,传入不定参数,则需要做一些改动,示例代码如下:

template<typename T> class Test; template<typename F, typename... Args> class Test<F(Args...)> { public: typedef F(*Callback)(Args... args); explicit Test(Callback callback) : callback(callback) {} void exec() { callback(11, 22, 33); } private: Callback callback; };

需要执行的C++普通函数

template<typename... Args> int TestFunction(Args... args) { std::list<int> arg_list = std::initializer_list<int>{args...}; while (!arg_list.empty()) { cout << arg_list.front() << endl; arg_list.pop_front(); } return 0; }

调用处:

Test<int(int, int, int)> test(TestFunction); test.exec();

运行结果:

11 22 33

代码说明:

模板类Test需要做一些改动,指定参数类型即可

template<typename F, typename... Args> class Test<F(Args...)>

调用出需要指定不定参数的类型和数量

Test<int(int, int, int)> test(TestFunction);//实例化模板 5、模板类传入不定参数的C++成员函数指针

和之前的demo不同,这里将上文的 TestClass 模板类型

template<typename M, typename T> class Test; template<typename M, typename F, typename... Args> class Test<M, F(Args...)> { public: typedef F(M::*TestCallback)(Args...); explicit Test(M *ptr, TestCallback func) : ptr(ptr), testCallback(func) { } void exec() { (*ptr.*testCallback)(11, 22, 33); } private: TestCallback testCallback; M *ptr; };

需要执行的类方法

template<typename ...Args> class TestClass { public: int TestFunction(Args... args) { std::list<int> arg_list = std::initializer_list<int>{args...}; while (!arg_list.empty()) { cout << arg_list.front() << endl; arg_list.pop_front(); } return 0; } };

调用处

template<typename... Args> void func() { using TC = TestClass<Args...>; TC testClass; Test<TC, int(Args...)> test(&testClass, &TC::TestFunction); test.exec(); } int main() { func<int, int, int>();//实例化 return 0; }

标签:结合