了解typename的双重意义——条款42

WPF数据可视化:LiveCharts自定义X轴与Y轴的5个实战技巧(附完整代码) 本文详细介绍了在WPF应用中使用LiveCharts进行数据可视化时,自定义X轴与Y轴的5个核心实战技巧。内容涵盖精确控制刻度步距、深度定制视觉样式、实现多轴布局对比、优化显示空间以及构建响应式动态轴,并提供了完整的C#和XAML代码示例,帮助开发者创建专业且用户体验出色的图表。 阅读详情

        提一个问题:以下template声明式中,class和typename有什么不同?

template<class T> class Widget;  //使用"class"
template<typenameT> class Widget;  //使用"typename"

        答案:没有不同。当我们声明template类型参数,class和typename的意义完全相同。某些程序员始终比较喜欢class,因为可以少打几个字。其他人比较喜欢typename,因为它暗示参数并非一定得是个class类型。少数开发人员在接受任何类型时使用typename,而只在接受用户自定义类型时保留旧式的class。然而从C++的角度来看,声明template参数时,不论使用关键字class或typename,意义完全相同。

        然而C++并不总是把class和typename视为等价。有时候你一定得使用typename。为了解其时机,我们必须先谈谈你可以在template内指涉(refer to)的两种名称。

        假设我们有个template function,接受一个STL兼容容器为参数,容器内持有的对象可被赋值为ints。进一步假设这个函数仅仅只是打印其第二元素值。这是一个无聊的函数,以无聊的方式实现,而且如稍后所言,它甚至不能通过便以。

template<typename C>
void print2nd(const C& container)    // 打印容器内第二个元素
{                                    // 注意这不是有效C++代码
    if (container.size() >= 2) {
        C::const_iterator iter(container.begin());    // 取得第一元素的迭代器
        ++iter;                                       // 将iter移往第二元素
        int value = *iter;                            // 将该元素复制到某个int
        std::cout << value;                           // 打印那个int
    } 
}

        在代码中特别强调两个local变量和itemvalue。iter的类型是C::const_iterator,实际是什么必须取决于template参数C。template内出现的名称如果相依于某个template参数,称之为从属名称。如果从属名称在class内呈嵌套状,我们称它 为嵌套从属名称。C::const_iterator就是这样一个名称。实际上它还是个嵌套从属类型名称,也就是个嵌套从属名称并且指涉某类型。

       print2nd内的另一个local变量value,其类型是int。int是一个并不依赖任何template参数的名称。这样的名称是非从属名称。

        嵌套从属名称有可能导致解析困难。举个例子,假设我们令print2nd更愚蠢些,这样起头:

template<typename C>
void print2nd(const C& container)
{
    C::const_iterator* x;
    ...
}

        看起来好像我们声明x为一个local变量,它是个指针,指向一个C::const_iterator。但它之所以被那么认为,只因为我们“已经知道”C::const_iterator不是个类型呢?如果C有个static成员变量而碰巧被命名为const_iterator,或如果x碰巧是个global变量名称呢?那样的话上述代码就不再是声明一个local变量,而是一个相乘动作:C::const_iterator乘以x。当然,这听起来有点疯狂,但却是可能的,而撰写C++解析器的人必须操心所有可能的输入,甚至是这么疯狂的输入。

        在我们知道C是什么之前,没有任何办法可以知道C::const_iterator是否为一个类型。而当编译器开始解析template print2nd时,尚未确知C是什么东西。C++有个规则可以解析此一歧义状态:如果解析器在template中遭遇一个嵌套从属名称,它便假设这个名称不是个类型,除非你告诉它是。所以缺省情况下嵌套从属名称不是类型。此规则有个例外,稍后会提到。

        现在再次看看print2nd起始处:

template<typename C>
void print2nd(const C& container)    
{                                    
    if (container.size() >= 2) {
        C::const_iterator iter(container.begin());    // 这个名称被假设为非类型
        ...

        现在应该很清楚为什么这不是有效的C++代码了吧。iter声明式只有在C::const_iterator是个类型时才合理,但我们并没有告诉C++说它是,于是C++假设它不是。若要矫正这个形势,我们必须告诉C++说C::const_iterator是个类型。只要紧临它之前放置关键字typename即可:

template<typename C>                 // 这是合法的C++代码
void print2nd(const C& container)    
{                                    
    if (container.size() >= 2) {
        typename C::const_iterator iter(container.begin());    
        ...

        一般性规则很简单:任何时候当你想要在template中指涉一个嵌套从属类型名称,就必须在紧临它的前一个位置放上关键字typename。

        typename只被用来验明嵌套从属类型名称:其他名称不该有它存在。例如下面这个function template,接受一个容器和一个“指向该容器”的迭代器:

template<typename C>                     // 允许使用“typename”(或“class”)
void f(const C& container,               // 不允许使用“typename”
        typename C::iterator iter);      // 一定要使用“typename”

        上述的C并不是嵌套从属类型名称(它并非嵌套于任何“取决于template参数”的东西内),所以声明container时并不需要以typename为前导,但C::iterator是个嵌套从属类型名称,所以必须以typename为前导。

        “typename必须作为嵌套从属类型名称的前缀词”这一规则的例外是,typename不可以出现在base classes list内的嵌套从属类型名称之前,也不可在member initialization list(成员初始列)中作为base class修饰符。例如:

template<typename T>
class Derived: public Base<T>::Nested {    // base class list中不允许“typename”
public:
    explicit Derived(int x)
    : Base<T>::Nested(x)                   // mem.init.list中不允许“typename”
    {
        typename Base<T>::Nested temp;     // 嵌套从属类型名称,
        ...                                // 既不在base class list中也不再mem.init.list中,
    }                                      // 作为一个base class修饰符需加上typename
    ...
};

        作为结语,我应该提到,typename相关规则在不同的编译器上有不同的实践。某些编译器接受的代码原本该有typename却遗漏了;原本不该有typename却出现了;还有少数编译器(通常是较旧版本)根本就拒绝typename。这意味typename和“嵌套从属类型名称”之间的互动,也许会在移植性方面带给你某种温和的头疼。

请记住

  • 声明template参数时,前缀关键字class和typename可互换。
  • 请使用关键字typename标识嵌套从属类型名称;但不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。
[OpenCV]使用霍夫变换精准检测圆形原理详解与代码实战 dp`是累加器分辨率与图像分辨率的反比,例如`dp=1`时累加器与图像具有相同的分辨率,`dp=2`时累加器分辨率为图像的一半;`HoughCircles`函数的返回值`circles`是一个包含检测到的圆的参数列表,每个圆的格式为`(x, y, r)`,分别代表圆心的x坐标、y坐标和半径。可以使用`cv2.circle()`函数在原图上绘制出检测到的圆,并使用`cv2.imshow()`或`cv2.imwrite()`显示或保存结果图像。霍夫圆变换是霍夫变换的一种扩展,专门用于检测图像中的圆形轮廓。 阅读详情

相关推荐

影刀RPA:轻松搞定Excel表格自动化操作

影刀RPA是一款功能强大的自动化工具,通过模拟人类操作实现各种重复性任务的自动化。零代码操作:通过拖拽式流程设计器,无需编程基础即可快速上手。功能丰富:提供丰富的组件库,涵盖文件操作、数据处理等多种功能。高效稳定:支持多任务并行,确保任务的高效执行和稳定性。支持Python语法:内置数据表格,支持Python语法,对新手友好,同时具备循环功能。通过影刀RPA,您可以轻松实现Excel表格的拆分、列数据合并和归档工作的自动化。这不仅节省了手动操作的时间,还能确保数据处理的高效和准确,提升工作效率和管理水平。

watwrmoon的博客 2560

条款42:了解typename的双重意义

(1)声明template参数时,前缀关键字class和typename可互换;(2)请使用关键字typename标识嵌套从事类型名称;但不得在base class lists(基类)或member initialization list(成员初值列表)内以它作为base class修饰符。

依然爱猪的博客 1024

【无标题】ReaxFF拟合参数以及算法安装

ReaxFF拟合参数以及算法安装

zmzyzm的博客 1418

Effective C++条款条款42:了解typename的双重意义(Understand the two meanings of typename)

期待大家和我交流,留言或者私信,一起学习,一起进步!

CltCj的博客 906

智能网联汽车云控系统核心解析:车云数据交互协议设计与实践

本文深入解析了智能网联汽车云控系统的核心——车云数据交互协议的设计与实践。文章围绕“说什么”、“怎么说”及异常处理三大核心问题,详细阐述了二进制与结构体数据类型定义、TCP/UDP双通道传输机制、通用报文格式以及典型交互流程(如GLOSA车速引导),并分享了时间同步、坐标系定义等关键实战经验与避坑指南,为构建高效、可靠、安全的车云“神经系统”提供专业指导。

alice7model的博客 121

Claude Code 完整使用教程(2026最新版)

《Claude Code 完整使用教程(2026最新版)》摘要: Claude Code 是 Anthropic 公司推出的智能编程工具,通过自然语言对话实现代码编写、调试和重构。本教程基于 v2.1.101 版本,涵盖安装配置、核心功能及最新特性。主要内容包括: 多平台安装方式(macOS/Linux/Windows) 桌面应用专属功能如并行会话、定时任务和语音模式 模型选择指南(Sonnet/Opus/Haiku) 快速入门示例:5分钟创建Node.js项目 核心功能:代码读写、命令执行、Git集成等

程序猿_三产 1万+

C++const修饰变量,函数,类

c++常函数,const在类,函数,mutable的地址是返回值,不可以被更改,但是让const int*p=c的地址,这同时让*p的值不可以被更改,之所以这样做是因为让返回值类型对照上。const的作用是:在编写程序过程中,因为我们会调用各种函数,假如我们并不想让某个已经赋了初值的变量在程序运行过程中受到改变,因此我们用const来作为关键字来修饰。在上述代码中,b是a的一个引用,可是我们并无法通过b来改变a的值(因为被定义成了const),而c则可以,我们可以通过改变c的值来改变a和b。

hfeifjeaf的博客 903

UG二次开发GRIP创建drill工序

UG二次开发GRIP创建drill工序

qq285503851的博客 1694

c++typename

#include <iostream> #include <vector> #include <algorithm> //所有泛型算法 #include <functional>//所有函数对象 #include <ctime> template <typename container> void print_contain...

KingOfMyHeart的博客 297

注意力机制模块:注意力机制新宠:EMA 注意力(高效多尺度注意力),即插即用,涨点明显

无降维成为共识:越来越多的研究者意识到,传统注意力机制的通道降维操作会造成不可逆的信息损失。EMA 提出的“保留每个通道信息”理念正在成为新一代注意力模块的设计标准。分组并行走向成熟:特征分组 + 并行处理的设计范式已在多个前沿架构中得到验证,兼顾了表达能力和计算效率。多尺度与跨空间融合:单纯的多尺度或单纯的跨空间交互都已无法满足复杂任务需求,两者的深度融合是当前的主流方向。边缘部署导向:2026 年的新论文越来越关注在资源受限设备上的高效运行,轻量化设计成为评估注意力模块的重要指标。

ZXSXJ的博客 948

智能车图像处理3-入门级分析2 ---直道冲刺

PS :入门级文章适合新手,如果已经有基础可以去看进阶篇文章。

taiyuezyh的博客 4299

条款42:了解typename的双重意义。

在模板的的声明中,class与typename是没有什么区别的: template T func1(const T&); template T func2(const T&); 但是在模板的定义中typename有时候却会派上用场。为了说明问题,我们先了解一下两个名词:从属名称和非从属名称。从属名称是依赖于某个类型的,比如迭代器,它是依赖于你的容器类型的;而非从属名称就不依赖其他类型,比如

thefutureisour的专栏 6997

RHEL 8 与 RHEL 7 与 RHEL 6 的比较,RHEL 8强到离谱!

Red Hat Enterprise Linux(RHEL)是企业级 Linux 发行版中最受欢迎的操作系统之一。RHEL 为服务器和企业环境提供了高性能、稳定性和安全性,适用于各种数据中心和云计算平台。自 RHEL 6 以来,Red Hat 对其操作系统进行了多次重大更新,RHEL 7 和 RHEL 8 带来了许多新的特性、工具和架构变化。

网络技术联盟站 705

条款42:了解typename的双重意义

template<class T> class Widget; //使用class template<typename T> classWidget; //使用typename 当我们声明template类型参数,class和typename的意义完全相同

L_H_L的博客 211

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Effective C++ 条款42:了解 typename 的双重意义

关键字 在 C++ 中有两种主要用途:标识嵌套从属类型名称 当指涉模板中的嵌套从属类型名称时,必须使用关键字 来明确表示该名称是类型,而不是变量或其他实体。声明模板参数 在声明模板参数时, 和 关键字可以互换使用。在模板中,当使用嵌套从属类型名称(即依赖于模板参数的类型名称)时,需要在名称前添加 :分析:在声明模板参数时,可以使用 或 ,两者等效:在基类列表和成员初始化列表中,不允许将 用作基类修饰符:总结:必须使用 的场合:不得使用 的场合: 与 的选择:通过正确理解和使用 ,可以有效避免

weixin_42255569的博客 573

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Effective C++ 条款42 了解typename的双重意义

1. 在template的声明式中,typename的使用和class完全相同,即以下两种声明方式完全相同 template<typename T> template<class T> 然而typename还有其他用途:指明嵌套从属类型名称. 2. 嵌套从属类型名称:如果template中某个名称依赖于类型参数,那么它就是从属名称,如果这个从属名称...

ddzai7557的博客 158

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Effective C++条款42:了解typename的双重意义

考虑以下代码: template<class T> class Widget; template<typename T> class Widget; class和typename有什么不同? 答案:没有不同.当我们声明template类型参数,class和typename的意义完全相同。 然而C++并不总是把class和typename视为等价.有时候一定得使用typen...

qq_44800780的博客 198

条款42:了解typename的双重意义——233

文章目录从属类型、嵌套从属类型和非从属类型——234无论何时,请在嵌套从属类型名称前放上关键字typename——234typename 不可出现在base class list内的嵌套从属类型名称之前,也不可在member initializationlist中作为base class 修饰符——236总结——237 从属类型、嵌套从属类型和非从属类型——234 我们来看下面例子: templa...

缇珞的博客 292

EffectiveC++-条款42:了解 typename 的双重意义

## 一. 内容 1. 提一个问题,以下 template 声明式中,class 和 typename 有什么不同? ```cpp template class Demo; template class Demo; ``` 答案:没有不同。`当我们声明 template 类型参数时, class 和 typename 的意义完全相同`。 某些程序员喜欢 class,因为可以少打几个字。 其他人,包括我,比较喜欢 typename ,...

MoOtA 272

Effective C++条款42:模板与泛型编程——了解typename的双重意义

一、意义① 意义①:typename可以在template中声明类型参数 在template中声明类型参数时,typename和class是等价的,两者都可以 例如: //两者是等价的 template<class T> class Widget; template<typename T> class Widget; 二、意义② 意义②:可以用来声明某种类型 演示说明 现在我们有一个模板,其接受一个STL容器类型,然后打印容器中的第二个元素的值,但是这个模板可能会

www_dong的博客 266

Effective C++ 学习笔记 条款42 了解typename的双重意义

这样的名字称为非依赖名(non-dependent names)(我不知道为什么它们不叫独立名,如果你和我一样觉得“非依赖”这个词令人憎恶,我深表同情,但“非依赖”就是这类名字的术语,所以像我一样,翻个白眼然后接受它吧)。C 不是一个嵌套依赖类型名(它没有嵌套在任何依赖模板参数的东西内部),所以在声明 container 时不得在其前面加上 typename,但 C::iterator 是一个嵌套依赖类型名,因此必须在其前面加上 typename。你很快会习惯它的,毕竟你有很强的动机去这么做。

tus00000的博客 217

Effective C++ — 条款42:了解typename的双重意义

了解typename的双重意义 提到一个问题,

阿亮的博客 1077
上一篇: 了解隐式接口和编译期多态——条款41
下一篇: 学习处理模板化基类内的名称——条款43
OODeveloper
博客等级 码龄12年 43粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值