C++模板:辨别函数类型

在《C++ Template》中有一个辨识函数类型的模板技术,原文的例子貌似有些错误,这里做个对比验证,如有错误,请大家指出,原文的代码如下:

template<typename T>
class CompoundT {
public:
	enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 };
	typedef T BaseT;
	typedef T BottomT;
	typedef CompoundT<void> ClassT;
};

这是基本模板,接着需要定义一个基本模板的特化,用于识别函数类型:

template<typename T>
class CompoundT<T()> {
public:
	enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 };
	typedef T BaseT();
	typedef T BottomT();
	typedef CompoundT<void> ClassT;
};

这个经过特化的类模板可以识别无参的函数类型,为了灵活使用,原文通过一个模板函数来完成具体的识别工作,如下:

template<typename T>
void test(T){
	cout<<typeid(T).name()<<endl;
	cout<<(CompoundT<T>::IsFuncT)<<endl;
}

这个模板函数到底能不能工作呢,我们可以实地验证一下:

void fun(){}

int main(){

	test(fun);
	return 0;
}

发现输出的结果如下:

typeid(T).name() : PFvvE

CompoundT<T>:: IsFuncT : 0

显然,识别的结果是错误的,问题是出在test的定义上,注意到test的参数列表时(T),也就是说采用了传值方式,而如果传递的是函数,会发生decay,即将函数名称decay为函数指针,所以 T 被推断成了函数指针类型,而不是函数类型,所以上面定义的特化版本无法与之匹配。现在将test重新定义如下:(将T改成T&)

template<typename T>
void test(T&){
	cout<<typeid(T).name()<<endl;
	cout<<(CompoundT<T>::IsFuncT)<<endl;
}

再次执行相同的测试,结果如下:

typeid(T).name() : FvvE

CompoundT<T>:: IsFuncT : 1

可见,这样就可以正确识别函数类型了。此外,我们也可以看到模板函数与模板类结合使用的巨大优势,因为模板函数可以进行类型推断(类型演绎)。如果不使用函数模板,CompoundT的作用就大大下降了,因为不能写成CompoundT<fun>,因为fun不是一个类型,fun相当于类型的实例。为了更加具体地说明这一点,我们可以进行如下定义:

typedef void func();

这样就可以使用CompoundT<func>了,因为func现在是一个函数类型。

时间: 2024-10-08 06:04:34

C++模板:辨别函数类型的相关文章

【C++】用函数模板实现不同类型的两个数比较大小

//用函数模板实现不同类型的两个数比较大小 #include <iostream> using namespace std; template <class mytype> //定义函数模板 class Max { public: Max(mytype a, mytype b) { x=a; y=b; } mytype printMax() { return x>y?x:y; } private: mytype x,y; }; int main() { Max <int

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器

 1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPushButton> #include <QLabel> template<class T> class run { public: T w; void show() { w.show(); } void settext() { w.setText("A"); }

ASP.NET MVC 4 (七) 模板帮助函数

和普通HTML帮助函数不同,模板帮助函数不需要指定所用的HTML类型,MVC会推断选择合适的HTML元素,这让我们有更多的灵活性. 使用模板帮助函数 我们使用<ASP.NET MVC 4 (六) 帮助函数>中的数据模型和控制器继续后面的例子,使用模板帮助函数后改写编辑输入的视图: @model HelperMethods.Models.Person @{ ViewBag.Title = "CreatePerson"; } <h2>CreatePerson<

类模板和函数模板

函数模板: 函数模板全特化:所谓特化,是指相对普通模板的特化,是另外一个模板.但不是实例,只是模板 template <class T>                                      //普通函数模板,泛型T mymax(const T t1, const T t2){   return t1 < t2 ? t2 : t1;} template <>const char* mymax(const char* t1,const char* t2)  

函数模板,函数模板重载,可变参数模板,函数模板覆盖,通过引用交换数据

 1.函数模板初级,如果想使用模板,需要实例化,实例化的方式是加上<数据类型> #include <iostream> //函数模板可以对类型进行优化重载,根据类型会覆盖 //如果仍然要使用模板函数,需要实例化 template<class T> T add(T a, T b) { std::cout << "T add " << std::endl; return a + b; } int add(int a, int

关于函数模板和函数重载

1 内联函数: 1 取消了函数调用的环节. 2 对于内联代码,程序无需调到另一个位置执行代码,再跳回来.因此,内联函数的运行速度比常规的快,,但占用的空间业更多. 3 要成为内联函数,要在函数定义或者声明前加关键字 inline 例如:inline int square() { } 4 内联函数中不允许用循环语句和switch语句 5 内联函数的声明必须出现在内联函数第一次调用之前 2  函数重载 1 函数名相同,参数不同,或者是函数类型不同 例如:   void swap(int a,int

C++入门经典-例9.1-函数模板,函数模板的作用,使用数组作为模板参数

1:函数模板不是一个实在的函数,因此编译器不能为其生成可执行的代码.定义函数模板只是一个对函数功能框架的描述,在具体执行时,将根据传递的实际参数决定其功能. 2:函数模板定义的一般形式如下: template <类型形式参数> 返回类型 函数名(形式参数表) { ...//函数实现 } 其中template为关键字,表示定义一个模板,尖括号"<>"中为模板参数,模板参数主要有两种,一种是模板类型参数,另一种是模板非类型参数.上述代码中定义的模板使用的是模板类型参

类模板和函数模板引发的思考

首先我们在学习类模板和函数模板时候会遇到这样一个问题: 类模板 与模板类 函数模板与模板函数 这些不仅仅是简单的文字游戏,而是需要我们深深的区分一下才可以理解其中的奥秘! 再回想一下我们在学习C语言的时候也遇到了这样几个类似的名词 函数指针与指针函数 数组指针与指针数组 函数指针即是重点在后边的名词指针,前边的函数只是修饰名词指针的一个定语而已,欧,这是一个语文的奥秘哟,忽然觉得自己好博学,言归正传,重点在指针,那就是指向一个函数的指针,其中保存了这个函数的地址通过指针解引用可以调用这个函数 就