模板类成员函数特化写法

昨天有对模板类的函数成员特化需求,目的是为了对不同模板参数实现不同的操作,结果在写过程中碰到already defined的问题(貌似是模板新手最容易碰到的问题了),类外的成员函数和同在类外的特化版本成员函数冲突了。因为对模板用法不是很熟悉,找了半天发现网上一段对话:


gcc下面,判断函数是不是内联,是看函数实现的地方的,类里面的函数,在gcc开启优化的时候,会自动加上inline,如果在类里面实现,那就可能是inline函数,如果在类外实现那就基本不会是inline(除非开O3)

普通函数我是在类里面实现的,特化函数在类外面实现,不加inline编译不过,说重定义了


这里说到一点就是未特化的模板函数是放在类定义里面用inline实现的,然后特化版本定义在外面,不然同在类外就会重定义。

问题解决!


顺便记录一下在用模板时碰到的问题以及看到的文章的摘抄:

C++ Template学习笔记之函数模板确是不错的文章,经验性的东西的总结配合自己试着去写,是最快的入门方式。

摘抄一些让人有所启发的地方:


通过将关键字typename引入到C++中,我们可以对模板定义进行分析。为了分析模板定义,编译器必须能够区分出是类型以及不是类型的表达式。如(Parm代表一个类):
   template <class Parm,class U>
   Parm minus(Parm* array,U value)
   {
   Parm::name * P; // 这是一个指针声明还是乘法?答案是乘法
   }
   编译器不知道name是否为一个类型,因为它只有在模板被实例化之后才能找到Parm表示的类的定义。为了让编译器能够分析模板定义,用户必须指示编译器哪些表达式是类型表达式。告诉编译器一个表达式是类型表达式的机制是在表达式前加上关键字typename。如:
   template <class Parm,class U>
   Parm minus(Parm* array,U value)
   {
   typename Parm::name * P; // 这是指针声明
   }


显式模板实参:
template <class T>
   T min5( T, T ) {/* . . . */ }
   // min5( unsigned int, unsigned int ) 被实例化
   min5< unsigned int >( ui, 1024 );
显式模板实参应该只被用在完全需要它们来解决二义性,或在模板实参不能被推演出来的上下文中使用模板实例时。大部分情况依赖自动解析。


模板编译模式
一、包含编译模式
   在包含编译模式下,我们在每个模板被实例化的文件中包含函数模板的定义,并且往往把定义放在头文件中,象内联函数所做的那样。如:
   // model1.h
   // 包含模式:模板定义放在头文件中
   template <typename Type>
   Type min( Type t1, Type t2 ) {
   return t1 < t2 ? t1 : t2;
   }
   在每个使用min()实例的文件中都包含了该头文件,如:
   // 在使用模板实例之前包含模板定义
   #include "model1.h"
   int i, j;
   double dobj = min( i, j );
   该头文件可以被包含在许多程序文本文件中。这意味着编译器必须在每个调用该实例的文件中实例化min()的整型实例吗?不。该程序必须表现得好像min()的整型实例只被实例化一次。但是,真正的实例化动作发生在何时何地,要取决于具体的编译器实现。
  二、分离编译模式
   在分离编译模式下,函数模板的声明被放在头文件中。在这种模式下,函数模板声明和定义的组织方式与程序中的非内联函数的声明和定义组织方式相同。如:
   // model2.h
   // 分离模式:只提供模板声明
   template <typename Type> Type min( Type t1, Type t2 );
   // model2.c
   // 模板定义
   export template <typename Type>
   Type min( Type t1, Type t2 ) {/* . . . */}
   使用函数模板min()实例的程序只需在使用该实例之前包含这个头文件:
   // user.c
   #include "model2.h"
   int i, j;
   double d = min( i, j ); // OK: 用法,需要一个实例
   我们通过在模板定义中的关键字template之前加上关键字export,来声明一个可导出的函数模板。(在CPP文件中定义模板函数体的方法)
  三、显式实例化声明
   标准C++提供了显式实例化声明来帮助程序员控制模板实例化发生的时间。在显式实例化声明中,关键字template后面是函数模板实例的声明,其中显式地指定了模板实参。下例中提供了sum(int* , int)的显式实例化声明:
   template <typename Type>
   Type sum( Type op1, int op2 ) {/* . . . */} // 函数模板sum的定义必须给出
   // 显式实例化声明
   template int* sum< int* >( int*, int );
   该显式实例化声明要求用模板实参int*实例化模板sum()。对于给定的函数模板实例,显式实例化声明在一个程序中只能出现一次。




模板函数的实例化会选择最特化的(most specialized)模板函数,如
   template <typename Type>
   Type sum( Type*, int );
   template <typename Type>
   Type sum( Type, int );
   int ia[1024];
   // Type==int; sum<int>( int*, int ); or
   // Type==int*; sum<int*>( int*, int); ??
   int ival1 = sum<int>( ia, 1024 );
最特化的是type*版本



这里
展开阅读全文

没有更多推荐了,返回首页