如何在C++模板中声明函数?及实现需函数实例化的模板类?
嘿,我来帮你搞定这两个C++模板相关的问题!
问题1:如何在C++模板声明中声明函数?
在C++模板里,你有几种方式来声明和使用函数作为模板的一部分,核心是根据需求选择编译期绑定还是运行期灵活绑定:
方式1:直接用函数类型作为非类型模板参数
这种方式是把函数本身作为模板参数,编译期就确定绑定的函数,性能很好。比如我们声明一个模板,接受一个"输入两个int、返回bool"的函数:// 模板声明中直接指定函数签名 template <bool Func(int, int)> class TemplateWithFunc { public: void run(int a, int b) { bool result = Func(a, b); // 这里可以基于result做逻辑处理 } }; // 定义一个符合签名的函数 bool isGreater(int x, int y) { return x > y; } // 实例化模板时传入函数 TemplateWithFunc<isGreater> myObj;方式2:用函数指针作为非类型模板参数
和上面的效果几乎一样,只是写法上明确用指针形式,可读性更强一点:template <bool (*FuncPtr)(int, int)> class TemplateWithFuncPtr { public: void execute(int a, int b) { bool res = FuncPtr(a, b); } }; // 实例化方式和上面一致 TemplateWithFuncPtr<isGreater> anotherObj;方式3:用类型模板参数+std::function(灵活支持各种可调用对象)
如果需要支持lambda、仿函数这类不是普通函数的可调用对象,就可以用这种方式,把函数类型作为模板参数,在构造时传入具体的函数对象:#include <functional> template <typename FuncType> class FlexibleTemplate { private: FuncType func_; public: // 构造时传入函数对象 FlexibleTemplate(FuncType func) : func_(func) {} void doWork(int a, int b) { bool res = func_(a, b); } }; // 实例化时可以传普通函数,也可以传lambda auto lambda = [](int x, int y) { return x < y; }; FlexibleTemplate<decltype(lambda)> flexibleObj(lambda); // 甚至可以用auto简化实例化代码 auto flexibleObj = FlexibleTemplate(lambda);
问题2:实现类似Ada中需传入函数才能实例化的泛型(模板)
Ada里那种必须传入指定签名的函数才能实例化泛型包的场景,在C++里用非类型模板参数就能完美实现,本质和问题1的方式1/2一致,我们拿你提到的Stack类举个具体例子:
假设我们的Stack需要一个签名为bool Sum(T, T)的函数(T是栈的元素类型),用来判断两个元素的某种求和相关条件,实现步骤如下:
定义带函数参数的模板类
template <typename T, bool (*SumFunc)(T, T)> class Stack { private: T elements[100]; int top_ = 0; public: void push(T elem) { if (top_ < 100) { elements[top_++] = elem; } } // 利用传入的SumFunc实现业务逻辑 bool checkTopTwoSum() { if (top_ >= 2) { // 调用传入的SumFunc处理栈顶两个元素 return SumFunc(elements[top_-1], elements[top_-2]); } return false; } };定义符合签名的具体函数
// 针对int类型的Sum函数,比如判断两数之和是否大于10 bool Sum_Int(int a, int b) { return (a + b) > 10; }实例化模板(和Ada的写法非常相似)
// 传入元素类型int和Sum_Int函数,完成实例化 Stack<int, Sum_Int> myIntStack;
如果想要支持通用类型的函数,还可以定义模板函数,然后实例化时指定具体类型:
// 通用的Sum模板函数,适用于任意支持加法的类型 template <typename T> bool Sum_Generic(T a, T b) { return (a + b) > T{10}; } // 实例化Stack时指定函数的具体实例 Stack<double, Sum_Generic<double>> myDoubleStack;
要是你需要更灵活的绑定(比如运行时切换函数),可以用问题1里的方式3,把函数对象作为类的成员变量,在构造时传入,这样实例化时可以传入任何符合签名的可调用对象(lambda、仿函数都可以)。
内容的提问来源于stack exchange,提问作者Graham Tasker
相关产品推荐
相关产品推荐

