C++模板之typename和class关键字的区别

本文详细介绍了在C++中使用模板时typename与class关键字的区别,并通过具体示例展示了在涉及子类型的情况下,typename的重要性及其正确用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们都知道,在STL中基本上都使用了模板类的声明,即template。在模板类的声明中,我们有两种方式:

template <class T>
template <typename T>

在这里,class和typename是相同的。也就是说,在声明一个template type parameter(模板类型参数)的时候,class和typename意味着 
完全相同的东西。

但是,在C++中,有的时候必须要使用typename.下面我们列举下面一个例子。

关键字typename被用来作为型别之前的标识符号。

template <class T>
class MyClass{
    typename T::SubType * ptr;
    ...
};

在这里,typename指出SubType是class T中定义的一个类别,因此ptr是一个指向T::SubType型别的指针。如果没有关键字typename,SubType会被当成一个static成员,于是

T::SubType * ptr

会被解释为型别T内的数值SubType与ptr的乘积。

SubType成为一个型别的条件是,任何一个用来取代T的型别,其内部必须有一个内部型别(inner type)SubType的定义。例如,将型别Q当作template的参数。 
MyClass x;

必要条件是型别Q有如下的内部型别定义:

class Q{
    typedef int SubType;
    ...
};

因此,MyClass的ptr成员应该变成一个指向int型别的指针,子型别SubType也可以成为抽象 
数据型别(例如,class):

class Q{
    class SubType;
    ...
};

  

注意,如果要把一个template中的某个标识符号指定为一种类别,就算是意图显而易见,关键字typename也是不能省略的,因此C++的一般规则是,除了使用typename修饰之外,template内的任何标识符号都被视为一个值而不是一个类别(对象)。

 

总结:

  1. template<typename T>与template<class T>一般情况下这两个通用,但有一个特例,就是当 T 是一个类,而这个类又有子类(假设名为 innerClass) 时,应该用 template<typename>:
  2. typename T::innerClass myInnerObject;这里的 typename 告诉编译器,T::innerClass 是一个类,程序要声明一个 T::innerClass 类的对象,而不是声明 T 的静态成员,而 typename 如果换成 class 则语法错误。

 

转载于:https://www.cnblogs.com/cthon/p/9201649.html

<think>好的,我现在要仔细思考用户的问题:“请介绍一下类型参数使用typenameclass关键字区别。” 用户之前已经询问过非类型模板参数类型模板参数的区别,现在进一步深入,想了解在声明类型模板参数时,使用typenameclass这两个关键字有什么不同。 首先,我需要回忆C++模板的基本知识。在模板声明中,类型参数通常用typenameclass关键字来声明。例如: template<typename T> class MyClass { ... }; 或者 template<class T> class MyClass { ... }; 看起来这两个关键字在这里的作用是一样的。那用户想知道它们的区别,可能是在某些特定情况下,这两个关键字有不同的用途或限制。 接下来,我需要确认是否在标准中有明确规定它们的区别。根据C++标准,在模板参数声明中,typenameclass是可以互换的,没有功能上的区别。也就是说,无论使用哪一个,编译器都会以同样的方式处理。 但可能存在一些历史原因或习惯用法。例如,class关键字是在C++的早期版本中引入的,用于声明类型参数,而后来typename被加入,可能为了增加可读性,特别是在处理嵌套依赖类型时需要使用typename的情况。 不过,在模板参数声明的位置,typenameclass确实是等价的。但在模板内部,当引用依赖类型时,必须使用typename来告诉编译器某个名称是一个类型,而不是静态成员或其他。例如: template<typename T> void foo() { typename T::SubType * ptr; // 这里必须用typename } 这种情况下,typename的作用是告诉编译器T::SubType是一个类型,而不是静态成员变量。这可能用户在问题中提到的关键字使用场景不同,但用户的问题仅限于模板参数声明时的区别,因此这部分可能不需要展开,除非用户有后续的问题。 另外,可能存在一些编码风格上的差异。有些程序员喜欢在模板参数声明时使用typename,因为更直观地表明这是一个类型参数,而class可能让人误解为只能是类类型,但实际上类型参数可以是任何类型,包括基本类型如int、double等。因此,使用typename可能更准确,避免歧义。 我需要检查是否有例外情况,比如在某些情况下只能用其中一个关键字。例如,在模板模板参数中,是否必须使用class?例如: template<template<typename> class Container> // 这里是否只能用classclass Adapter { ... }; 根据C++标准,在C++17之前,模板模板参数声明必须使用class关键字,但C++17及以后允许使用typename。例如: template<template<typename> typename Container> // C++17允许 class Adapter { ... }; 这可能是一个区别,但用户的问题是否涉及模板模板参数呢?如果用户的问题仅限于普通的类型参数,而不是模板模板参数,那么这可能属于高级用法,可能需要提到,但需要明确说明。 总结一下,可能的回答结构是: 1. 在普通类型模板参数声明中,typenameclass完全等价,没有区别。 2. 历史原因:class是早期引入的,typename后来加入,更清晰表明可以是任何类型。 3. 编码风格建议:使用typename以避免误解,尤其是当参数可以是基本类型时。 4. 例外情况:在模板模板参数中,C++17之前必须用class,之后可以用typename。 5. 其他上下文中typename的用途(如嵌套依赖类型),但这里用户的问题可能不涉及。 需要确保回答准确,同时避免混淆用户。要明确指出在声明类型参数时两者无区别,但在其他情况下typename有其他用途。 现在,可能存在的误区是用户可能认为两者在参数声明时有功能差异,需要澄清。另外,可能需要提到,某些旧的代码或教材可能习惯使用class,而现代代码更倾向typename,但两者在功能上是相同的。 最后,是否有其他需要注意的地方?例如,别名模板中使用的情况,或者概念(C++20)中的使用?不过概念可能超出了当前问题的范围。 因此,最终的回答应该包括: - 两者在声明类型参数时等价。 - 历史背景编码风格建议。 - 模板模板参数中的区别C++17前后)。 - 其他上下文中typename的用途(可选提及,以区分)。 需要确保回答简洁明了,符合用户的知识水平,可能用户是正在学习模板C++开发者,需要明确的指导。</think>以下是关于C++模板中`typename``class`关键字在**声明类型参数**时的区别解析: --- ### **1. 核心结论** 在模板参数声明中,`typename``class` **完全等价**,编译器会以相同方式处理: ```cpp // 两种声明方式完全等效 template<typename T> void foo(); // ✅ 现代常用 template<class T> void bar(); // ✅ 传统写法 ``` --- ### **2. 历史背景** | 关键字 | 引入时间 | 设计初衷 | |-----------|-----------|-----------------------------------| | `class` | C++98 | 早期模板仅支持类类型作为参数 | | `typename`| C++03 | 明确允许所有类型(包括基本类型) | --- ### **3. 现代编码建议** | 场景 | 推荐使用 | 原因 | |--------------------------|----------------|----------------------------------------------------------------------| | **通用类型参数** | `typename` | 更清晰表明可以是任意类型(`int`、`double`等,不限于类类型) | | **模板模板参数** | `class`或`typename`(C++17+) | C++17前必须用`class`,C++17后允许`typename`(见下文示例) | | **强调参数必须为类类型** | `class` | 通过命名约定提示使用者(但技术上仍允许非类类型,编译器不会检查) | --- ### **4. 关键差异场景** #### **① 模板模板参数声明** ```cpp // C++17前必须用 class template<template<typename> class Container> // ✅ 传统写法 struct OldAdapter { /*...*/ }; // C++17起允许用 typename template<template<typename> typename Container> // ✅ 现代写法(C++17+) struct NewAdapter { /*...*/ }; ``` #### **② 非类型参数的误导性** ```cpp template<class N> // ❗ 容易误解N必须是类类型,实际可以是int等基础类型 void func() { /*...*/ } template<typename N> // ✅ 更清晰地表明N可以是任何类型 void better_func() { /*...*/ } ``` --- ### **5. 其他语境中`typename`的独特作用** 在模板**内部**引用**嵌套依赖类型**时,必须使用`typename`: ```cpp template<class T> struct MyStruct { typename T::NestedType x; // ✅ 必须加typename // class T::NestedType y; // ❌ 语法错误 }; ``` --- ### **6. 编码规范建议** | 代码风格 | 适用场景 | |-------------------|-----------------------------------------| | **统一用`typename`** | 新项目推荐,强调参数可以是任意类型 | | **统一用`class`** | 维护旧代码库时保持一致性 | | **混合使用** | 不推荐,除非有明确语义区分需求 | --- ### **7. 总结对比表** | 维度 | `typename` | `class` | |--------------------|-------------------------------------|----------------------------------| | **模板参数声明** | ✅ 所有类型(推荐) | ✅ 所有类型(历史遗留) | | **模板模板参数** | ✅ C++17+ | ✅ 所有版本 | | **代码可读性** | 更清晰(尤其是基础类型) | 可能误导用户以为只能是类类型 | | **依赖类型声明** | ✅ 必须使用(如`typename T::Sub`) | ❌ 不能用于此场景 | --- ### **8. 最终结论** - **功能等价性**:声明类型参数时,`typename``class`无任何技术差异 - **最佳实践**: - 新代码优先用`typename`(更准确表达语义) - 旧代码保持用`class`(维护一致性) - **注意陷阱**:在模板内部声明依赖类型时,必须用`typename`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值