111 C++ typename

2024-02-17 23:28
文章标签 c++ 111 typename

本文主要是介绍111 C++ typename,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍typename之前,应先了解几个概念:

1. 限定名与非限定名

限定名,顾名思义,是限定了命名空间的名称。

#include <iostream>int main()  
{std::cout << "Hello world!" << std::endl;
}


std::限定了std这个命名空间,故称为限定名。

#include <iostream>
using namespace std;int main()  
{cout << "Hello world!" << endl;
}


使用了using namespace std,就不再需要std::限定,此时cout和endl叫做非限定名

2. 依赖名与非依赖名


依赖名是指依赖于模板参数的名称,

非依赖名指不依赖模板参数的名称。

template <class T>
class MyClass {int i;vector<int> vi;vector<int>::iterator vitr;T t;        //由于依赖于模板参数T,只有在模板实例化的时候才能知道他们的类型vector<T> vt;vector<T>::iterator viter;
};


T、vector<T>和vector<T>::iterator称为依赖名,

int、vector<int>和vector<int>::iterator称为非依赖名。

3. 类作用域


类外部访问类中的名称时,存在三种方式:

1)静态数据成员

2)静态成员函数

3)嵌套类型

struct MyClass {
    static int A;
    static int B();
    typedef int C;
}
可分别使用MyClass::A、MyClass::B和MyClass::C表示

4. 引入typename的原因


来看下面一个例子:

 

template<class T>
void foo()
{T::iterator * iter;
}

T::iterator 这样的一个定义可以是以上三种类作用域中的任意一种类型。
(1)如果iterator是嵌套类型将正确执行,这段代码的意思是定义一个 T::iterator类型的数据。
(2)当iterator是静态数据成员时,以上代码将被解释为两个数相乘,返回值抛弃。如果iter没有定义,将报错;但如果iter是全局变量,将执行。
在模板实例化之前完全没有办法区分,因此,有必要引入新的关键字typename来区分这两种情况。

5. typename


5.1 基本使用


c++标准中有这么一句话:

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.
对于用于模板定义的依赖于模板参数的名称,只有在实例化的参数中存在这个类型名,或者这个名称前使用了typename关键字来修饰,编译器才会将该名称当成是类型。除了以上这两种情况,绝不会被当成是类型。

上面的例子可以修改为:

 

template<typename T>void print2nd(const T& container){typename T::iterator* x;  //让编译器确定T::iterator是一个类型,不是一个变量,而不需要等到实例化时确定//...}


5.2 使用规则


以下情况禁止使用typename:

1)模板定义之外,即typename只能用于模板的定义中

2)非限定类型,比如前面介绍过的int,vector<int>之类

3)基类列表中,比如class Derived :public Base<T>::Nested不能在public Base<T>::Nested前面加typename

4)构造函数的初始化列表中

template<typename T>class Derived :public Base<T>::Nested //此处不可以使用typename{public:explicit Derived(int):Base<T>::Nested(x)//此处不可以使用typename{typename Base<T>::Nested temp; //此处可以使用typename}


 

5.3 traits中的使用


代码示例:

template<typename IterT>
 
void workWithIterator(IterT iter)
 
{
 
    typename std::iterator_traits<IterT>::value_type temp(*iter);
 
    //...
 
}
此处我们使用到了iterator_traits<>模板类,其实是一种traits类。我们传递给其一个迭代器类型为其进行实例化,那么我们就可以通过其value_type萃取出迭代器所指的容器的类型。例如:

        1)如果IterT是list<string>::iterator,那么value_type就代表string,temp的类型就是string

        2)如果IterT是vector<int>::iterator,那么value_type就代表int,temp的类型就是int

因为value_type也是一种内嵌类型,因此我们需要使用typename声明其是一种类型

如果上面的代码比较复杂,那么我们还可以搭配typedef来使用,typedef是声明一个类型的别名。

template<typename IterT>
 
void workWithIterator(IterT iter)
 
{
 
    typedef typename std::iterator_traits<IterT>::value_type value_type; //为类型声明别名
 
    value_type temp(*iter); //使用类型定义变量
 
    //...
 
}
stl源码中有很多类似的例子,例如:

typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
它表示:将__type_traits<T>这个模板类中的has_trivial_destructor嵌套类型定义一个叫做trivial_destructor的别名

6 总结
Effective C++条款42:模板与泛型编程(了解typename的双重意义)中有如下总结:

1)声明template参数时,前缀关键字class和typename可互换

2)请使用关键字typename标识嵌套从属类型名称;但不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符

这篇关于111 C++ typename的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/719312

相关文章

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

利用Python和C++解析gltf文件的示例详解

《利用Python和C++解析gltf文件的示例详解》gltf,全称是GLTransmissionFormat,是一种开放的3D文件格式,Python和C++是两个非常强大的工具,下面我们就来看看如何... 目录什么是gltf文件选择语言的原因安装必要的库解析gltf文件的步骤1. 读取gltf文件2. 提

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快