Effective C++笔记之八:template中的class、typename关键字

本文深入探讨了C++中template的使用技巧,特别是class与typename的区别及typename在处理嵌套从属类型名称时的重要作用。

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

       template 声明式中,class 和 typename 这两个关键字意义完全相同

template<class T> class Widget;
template<typename T> class Widget;

       有时候你一定要用 typename。

template <typename C> 
void print2nd(const C& container) 
{ 
    if (container.size() >= 2) 
    { 
        C::const_iterator iter(container.begin()); 
        ++iter; 
        int value = *iter; 
        std::cout << value; 
    } 
}

       iter 的类型是C::const_iterator实际上是什么必须取决于template 参数C。template内出现的名称如果相依于某个template参数,称之为从属名称(dependent names)。如果从属名称在class内呈嵌套状,称之为嵌套从属名称(nested dependent name)。C::const_iterator就是这样一个名称嵌套从属名称。value类型int,不依赖任何template参数的名称,称为非从属名称(non-dependent name)。
       嵌套从属名称可能导致解析的困难:

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

       看起来我们好像声明一个local变量,是个指针,指向一个C::const_iterator。 但它之所以被那么认为,是因为我们 “已经知道”C::const_iterator是个类型。如果C::const_iterator不是个类型呢?如果C有个static成员变量碰巧被命名为const_iterator。此时x碰巧是个global变量名称,那样上述代码就是一个相乘动作,C::const_iterator乘以x。撰写C++解析器的人必须操心所有可能的输入。
       在我们知道C以前,没有任何办法可以知道C::const_iterator是否为一个类型。而当编译器开始解析 template print2nd 时,尚未确定C是什么东西。
C++有个规则可以解析这一歧义状态:如果解析器在template 中遭遇一个嵌套从属名称,它便假设这个名称不是个类型,除非你告诉它是。缺省情况下从属名称不是类型。此规则还有个例外,后面会提到。
       所以上述代码不是有效的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()); 
        ++iter; 
        int value = *iter; 
        std::cout << value; 
    } 
}

       typename只用来验明嵌套从属类型名称,其他名称不该有它存在。

template <typename C> 
void f(const C& container,        // 不允许使用 typename 
       typename C::iterator iter);// 一定要使用 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例子:一个function template,他接受一个迭代器,而我们打算为该迭代器指涉的对象做一份复件temp:

template <typename IterT> 
void workWithIterator(IterT) 
{ 
    typename std::iterator_traits<IterT>::value_type temp(*iter); 
}

       如果IterT是 vector<int>::iterator,temp的类型就是int,如果IterT是list<string>::iterator,temp的类型就是string。由于std::iterator_traits<IterT>::value_type是个嵌套从属类型名称(value_type被嵌套于iterator_traits<IterT> 之内而IterT是个template参数),所以必须在它之前放置typename。
这么长你肯定会想建立一个typedef。

template <typename IterT>
void workWithIterator(IterT)
{
    typedef typename std::iterator_traits<IterT>::value_type value_type;
    value_type temp(*iter);
}


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

模板参数有三种类型:类型模板参数、模板的模板参数(以模板作为模板的参数)、非类型模板参数

详见:C++学习笔记:模板参数_胖小迪的博客-优快云博客_c++模板参数

<think>嗯,用户希望我作为一个资深C++程序员,帮助有一定基础的程序员制定提升计划。首先,我需要明确用户的当前水平。他说“有一定基础”,可能是指已经掌握了基本语法、面向对象编程,可能有过一些小项目经验。但具体基础到什么程度呢?可能需要分阶段来规划,从巩固基础到进阶,再到高级主题和实战。 接下来,我得考虑C++的核心知识点。比如,内存管理、模板、STL、多线程这些肯定是重点。用户可能已经知道一些,但需要系统化梳理。然后,现代C++的特性(C++11到C++20)也是必须的,因为很多项目已经转向新标准。 然后,项目实践很重要。光有理论不够,得通过实际项目来应用知识。可能需要建议不同类型的项目,比如网络服务、算法实现、性能优化等。开源贡献也是一个好方向,可以学习他人的代码,参与实际项目。 另外,计算机基础也不能忽视。数据结构和算法、操作系统原理、网络编程这些底层知识对提升编程能力至关重要。特别是对于C++程序员来说,理解底层机制能更好地优化代码。 用户可能还希望了解如何持续学习,比如阅读经典书籍、参与社区、技术博客等。这些都是长期提升的关键。同时,面试准备可能也是一个隐藏需求,毕竟很多程序员提升能力也是为了职业发展。 需要避免过于笼统的计划,应该分阶段,每个阶段有明确的目标和任务。比如第一阶段巩固核心基础,第二阶段深入高级特性,第三阶段实战和系统设计。每个阶段都要有理论学习和实践项目结合。 还要考虑用户的时间安排,制定一个合理的时间表,比如每周投入多少小时,每个阶段持续多久。但用户可能没有明确时间,所以计划要有灵活性。 最后,检查是否有遗漏的部分,比如调试技巧、性能分析工具的使用,这些在实际开发中非常重要。还有代码规范和设计模式,这些能提升代码质量和可维护性。</think>以下是为期6个月的C++能力提升计划,分为三个阶段,结合理论强化与实践项目,适合已掌握基础语法和面向对象编程的程序员: --- ### 第一阶段:夯实核心基础(2个月) #### 核心目标 1. **深入理解内存管理** - 精读《Effective C++》条款41-55 - 手写内存池(固定大小/可变块) - 调试10个内存泄漏案例(使用Valgrind/AddressSanitizer) 2. **STL源码剖析** - 研究vector/deque/map底层实现 - 实现简化版STL容器(建议从allocator入手) - 性能对比测试:vector vs原生数组 #### 实践项目 ```cpp // 实现线程安全的环形缓冲区 template<typename T, size_t Capacity> class RingBuffer { public: bool push(const T& item); // 考虑异常安全 bool pop(T& item); // 使用memory_order优化 private: std::atomic<size_t> head_{0}; std::atomic<size_t> tail_{0}; T data_[Capacity]; }; ``` --- ### 第二阶段:进阶技术突破(2个月) #### 关键技术点 1. **模板元编程** - 掌握SFINAE技巧 - 实现类型萃取(type_traits) - 编译期计算斐波那契数列 2. **并发编程实战** - 对比std::thread/pthread/OpenMP - 实现无锁队列(使用CAS指令) - 设计线程池(支持任务窃取) #### 推荐工具链 ```bash # 使用最新编译器特性验证 g++ -std=c++20 -Wall -Wextra -fsanitize=thread ``` --- ### 第三阶段:系统设计与优化(2个月) #### 实战方向 1. **高性能网络服务** - 基于asio实现HTTP服务器 - 压测对比epoll与select模型 - 实现自定义内存分配策略 2. **跨平台开发** - 使用CMake管理多平台构建 - 处理不同编译器兼容性问题 - 编写跨ABI的动态库接口 #### 性能优化案例 ```cpp // 热路径优化示例 void processData(std::vector<Data>& dataset) { // 优化点: // 1. 消除虚函数调用 // 2. 保证内存连续性 // 3. 预取指令优化 // 4. SIMD指令应用 } ``` --- ### 配套学习资源 1. **必读书籍**(按优先级排序): - 《C++ Concurrency in Action》(第二版) - 《深入理解C++对象模型》 - 《C++ Template Metaprogramming》 2. **进阶路线**: ```mermaid graph LR A[掌握C++17特性] --> B[理解ABI规范] B --> C[学习LLVM中间表示] C --> D[参与开源项目优化] ``` 3. **持续提升建议**: - 每月review一次标准委员会提案 - 参与CppCon会议视频学习 - 在GitHub维护技术博客(建议用Markdown记录学习笔记) 该计划强调"深度优先"的学习策略,每个技术点都要求完成可验证的产出物。建议每周保持至少20小时的专注学习时间,其中实践与理论的时间分配建议为3:2。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草上爬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值