C++/CLR泛型与C++模板的对比
发布时间:2008/8/23 0:00:00 访问次数:471
参数列表
参数列表与函数的信号(signature)类似:它标明了参数的数量和每个参数的类型,并把给每个参数关联一个唯一的标识符,这样在模板定义的内部,每个参数就可以被唯一地引用。
参数在模板或泛型的定义中起占位符(placeholder)的作用。用户通过提供绑定到参数的实际值来建立对象实例。参数化类型的实例化并非简单的文本替代(宏扩展机制就是使用文本替代的)。相反地,它把实际的用户值绑定到定义中的相关的形式参数上。
在泛型中,每个参数都表现为object类型或衍生自object的类型。在本文后面你可以看到,这约束了你可能执行的操作类型或通过类型参数声明的对象。你可以通过提供更加明确的约束来调整这些约束关系。这些明确的约束引用那些衍生出实际类型参数的基类或接口集合。
模板除了支持类型参数之外,还支持表达式和模板参数。此外,模板还支持默认的参数值。这些都是按照位置而不是名称来分解的。在两种机制之下,类型参数都是与类或类型名称关键字一起引入的。
参数列表的额外的模板功能
模板作为类型参数的补充,允许两种类型的参数:非类型(non-type)参数和模板参数。我们将分别简短地介绍一下。
非类型参数受常数表达式的约束。我们应该立即想到它是数值型或字符串常量。例如,如果选择提供固定大小的堆栈,你就可能同时指定一个非类型的大小参数和元素类型参数,这样就可以同时按照元素类别和大小来划分堆栈实例的类别。例如,你可以在代码片断1中看到带有非类型参数的固定大小的堆栈。
代码片断1:带有非类型固定大小的堆栈
template <class elemtype, int size>
public ref class tstack
{
array<elemtype> ^m_stack;
int top;
public:
tstack() : top( 0 )
{
m_stack = gcnew array<elemtype>( size );
}
};
// 带有默认值的模板声明
template <class elemtype, int size = 1024>
public ref class fixedsizestack {};
// 最多128个字符串实例的堆栈
fixedsizestate<string^, 128> ^tbs = gcnew fixedsizestack<string^, 128>;
// 最多1024个字符串实例的堆栈
fixedsizestack<string^> ^tbs = gcnew fixedsizestack<string^>;
{
template <class t, class container = deque<t> >
class queue;
template <class t, class allocator = allocator<t> >
class vector;
// ...
} 也可以提供默认的元素类型,如下所示:
// 带有默认的元素类型的模板声明
template <class elemtype=string^, int size=1024>
public ref class tstack {};
指针也可以作为非类型参数,因为对象或函数的地址在编译时就已知了,因此是一个常量表达式。例如,你可能希望为堆栈类提供第三个参数,这个参数指明遇到特定条件的时候使用的回调处理程序。明智地使用typedef可以大幅度简化那些表面上看起来很复杂的声明,如下所示:
typedef void (*handler)( ... array<object^>^ );
template <class elemtype, int size, handler cback >
public ref class tstack {};
void defaulthandler( ... array<object^>^ ){ ... }
template < class elemtype,
int size = 1024,
handler cback = &defaulthandler >
public ref class tstack {};
void demonstration()
{
// 默认的大小和处理程序
tstack<string^> ^ts1
参数列表
参数列表与函数的信号(signature)类似:它标明了参数的数量和每个参数的类型,并把给每个参数关联一个唯一的标识符,这样在模板定义的内部,每个参数就可以被唯一地引用。
参数在模板或泛型的定义中起占位符(placeholder)的作用。用户通过提供绑定到参数的实际值来建立对象实例。参数化类型的实例化并非简单的文本替代(宏扩展机制就是使用文本替代的)。相反地,它把实际的用户值绑定到定义中的相关的形式参数上。
在泛型中,每个参数都表现为object类型或衍生自object的类型。在本文后面你可以看到,这约束了你可能执行的操作类型或通过类型参数声明的对象。你可以通过提供更加明确的约束来调整这些约束关系。这些明确的约束引用那些衍生出实际类型参数的基类或接口集合。
模板除了支持类型参数之外,还支持表达式和模板参数。此外,模板还支持默认的参数值。这些都是按照位置而不是名称来分解的。在两种机制之下,类型参数都是与类或类型名称关键字一起引入的。
参数列表的额外的模板功能
模板作为类型参数的补充,允许两种类型的参数:非类型(non-type)参数和模板参数。我们将分别简短地介绍一下。
非类型参数受常数表达式的约束。我们应该立即想到它是数值型或字符串常量。例如,如果选择提供固定大小的堆栈,你就可能同时指定一个非类型的大小参数和元素类型参数,这样就可以同时按照元素类别和大小来划分堆栈实例的类别。例如,你可以在代码片断1中看到带有非类型参数的固定大小的堆栈。
代码片断1:带有非类型固定大小的堆栈
template <class elemtype, int size>
public ref class tstack
{
array<elemtype> ^m_stack;
int top;
public:
tstack() : top( 0 )
{
m_stack = gcnew array<elemtype>( size );
}
};
// 带有默认值的模板声明
template <class elemtype, int size = 1024>
public ref class fixedsizestack {};
// 最多128个字符串实例的堆栈
fixedsizestate<string^, 128> ^tbs = gcnew fixedsizestack<string^, 128>;
// 最多1024个字符串实例的堆栈
fixedsizestack<string^> ^tbs = gcnew fixedsizestack<string^>;
{
template <class t, class container = deque<t> >
class queue;
template <class t, class allocator = allocator<t> >
class vector;
// ...
} 也可以提供默认的元素类型,如下所示:
// 带有默认的元素类型的模板声明
template <class elemtype=string^, int size=1024>
public ref class tstack {};
指针也可以作为非类型参数,因为对象或函数的地址在编译时就已知了,因此是一个常量表达式。例如,你可能希望为堆栈类提供第三个参数,这个参数指明遇到特定条件的时候使用的回调处理程序。明智地使用typedef可以大幅度简化那些表面上看起来很复杂的声明,如下所示:
typedef void (*handler)( ... array<object^>^ );
template <class elemtype, int size, handler cback >
public ref class tstack {};
void defaulthandler( ... array<object^>^ ){ ... }
template < class elemtype,
int size = 1024,
handler cback = &defaulthandler >
public ref class tstack {};
void demonstration()
{
// 默认的大小和处理程序
tstack<string^> ^ts1