typename 的高级用法2

  1. // stack5.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. #include <deque>
  6. #include <string>
  7. #include <exception>
  8. using namespace std;
  9. template <class T>
  10. class CStack
  11. {
  12. public:
  13.     void push(T const&);
  14.     void pop();
  15.     T top() const;
  16.     bool empty() const;
  17.     template <class T2>
  18.     CStack<T>& operator = (CStack<T2> const&);
  19. private:
  20.     deque<T>    m_dqElems;  
  21. };
  22. template <class T>
  23. void CStack<T>::push(T const& elem)
  24. {
  25.     m_dqElems.push_back(elem);
  26. }
  27. template <class T>
  28. void CStack<T>::pop()
  29. {
  30.     if (m_dqElems.empty())
  31.     {
  32.         throw out_of_range("empty stack!");
  33.     }
  34.     m_dqElems.pop_back();
  35. }
  36. template <class T>
  37. T CStack<T>::top() const
  38. {
  39.     if (m_dqElems.empty())
  40.     {
  41.         throw out_of_range("empty stack!");
  42.     }
  43.     return m_dqElems.back();
  44. }
  45. template <class T>
  46. bool CStack<T>::empty() const
  47. {
  48.     return m_dqElems.empty();
  49. }
  50. template <class T>
  51. template <class T2>
  52. CStack<T>& CStack<T>::operator = (CStack<T2> const& op2)
  53. {
  54.     if ((void*)this == (void*)&op2)// 判断是否赋值给自己
  55.     {
  56.         return *this;
  57.     }
  58.     CStack<T2> tmpOp2(op2);// 建立 op2 的一份拷贝
  59.     m_dqElems.clear(); // 移除所有现有元素
  60.     while (!tmpOp2.empty())
  61.     {
  62.         m_dqElems.push_front(tmpOp2.top());
  63.         tmpOp2.pop();
  64.     }
  65.     return *this;
  66. }
  67. int _tmain(int argc, _TCHAR* argv[])
  68. {
  69.     int i = 0;
  70.     CStack<int> intStack;
  71.     CStack<float> floatStack;
  72.     for (i = 0; i < 10; i++)
  73.     {
  74.         intStack.push(i);
  75.     }
  76.     floatStack = intStack;
  77.     cout << "floatStack contents: " << endl;
  78.     while (!floatStack.empty())
  79.     {
  80.         cout << floatStack.top() << "/t";
  81.         floatStack.pop();
  82.     }
  83.     cout << endl;
  84.     return 0;
  85. }


实作这个运算符(成员函数)时,你可能希望取得「赋值符号右侧之op2 stack」的所有必要资料,但是这个stack的类型和目前(此身)类型不同(是的,如果你以两个不同的类型实例化同一个classtemplate,你会得到两个不同的类型),所以只能通过public接口来得到那些数据。 因此惟一能够取得 op2 数据的办法就是调用其 top()函数。你必须经由 top()取得op2 的所有数据,而这必须借助 op2 的一份拷贝来实现:每取得一笔数据,就运用 pop()把该数据从op2 的拷贝中移除。由于top()传回的是stack之中最后(最晚)被推入的元素,所以我们需要反方向把元素安插回去。基于这种需求,这里使用了deque,它提供push_front()操作,可以把一 个元素安插到容器最前面。有了这个 member template,你就可以把一个 int stack 赋值(assign)给一个 float stack:

Stack<int> intStack1, intStack2; //stack for ints
Stack<float> floatStack; //stack for floats
...
floatStack = intStack1; // OK:两个 stacks 类型不同,但 int 可转型为 float。

当然,这个赋值动作并不会改动 stack和其元素的类型。赋值完成后,floatStack 的元素类型还是 float,而 top()仍然传回 float 值。也许你会认为,这么做会使得类型检查失效,因为你甚至可以把任意类型的元素赋值给另一个 stack。然而事实并非如此。必要的类型检查会在「来源端 stack」的元素(拷贝)被安插到「目 的端 stack」时进行:

elems.push_front(tmp.top());

如 果 你将一个 string stack 赋值 给一个 float stack , 以 上 述 句 编译时就会发生错 误: 「elems.push_front()无法接受 tmp.top()的返回类型」。具体的错误讯息因编译器而异,但 含义类似。

Stack<std::string> stringStack; // stack of strings
Stack<float> floatStack; // stack of floats
floatStack = stringStack; // 错误:std::string 无法转型为 float

注意,前述的 template assignment 运算符并不取代 default assignment 运算符。如果你在相同 类型的 stack 之间赋值,编译器还是会采用 default assignment 运算符。
<think>嗯,用户想了解C++模板的现代高级用法。首先,我需要确定用户的基础,可能已经了解模板的基本概念,比如函数模板和类模板。接下来,要整理现代C++(C++11及之后)引入的新特性,这些特性如何增强模板的功能和应用场景。 首先想到的是变参模板(Variadic Templates),这是C++11的重要特性,允许模板接受可变数量的参数,应用广泛,比如实现元组、函数包装器等。需要解释其基本用法和典型应用案例,比如递归展开和折叠表达式。 然后是别名模板(Alias Templates),C++11引入的using语法可以定义模板别名,简化复杂类型,特别是结合类型特征时。这部分需要说明和typedef的区别,以及如何提升可读性。 接下来是SFINAE和概念(Concepts)。SFINAE是模板元编程中的关键技术,用于在编译时根据类型特性选择不同的模板特化。而C++20引入的概念(Concepts)进一步简化了约束条件的编写,替代了复杂的SFINAE技巧。需要对比两者的使用方式,强调概念带来的简洁性。 constexpr和编译时计算也是现代模板的重要部分。C++11开始,constexpr允许在编译时执行计算,结合模板可以实现编译时的算法和类型操作,比如编译时排序、斐波那契数列计算等。C++17的constexpr if更是简化了编译时条件分支的处理。 模板元编程(TMP)的现代演进,比如使用constexpr函数替代传统的递归模板实例化,减少代码复杂性和编译时间。同时,变量模板(C++14)作为模板的另一种形式,用于定义常量和类型特征,需要举例说明其优势。 折叠表达式(C++17)简化了变参模板的参数展开,避免了递归实例化的需要,提高代码效率和可读性。需要展示传统展开与折叠表达式的对比示例。 类型推导和自动返回类型(C++14的auto和decltype(auto))如何与模板结合,简化返回类型处理,特别是在复杂表达式中的类型推导问题。 模板的惰性求值,如表达式模板技术,用于优化数值计算库(如Eigen),延迟计算直到赋值,避免中间变量。这部分可能需要简要介绍,因为用户可能对具体实现不太熟悉,但需要说明其应用场景和好处。 最后,C++20的新特性:概念(Concepts)、约束(Requires)和范围(Ranges),这些如何与模板结合,提升代码的清晰度和安全性。特别是概念作为类型约束的显式表达,取代了enable_if的繁琐用法。 在整理这些内容时,需要确保每个特性都有明确的示例代码,并说明其解决的问题和优势。同时要注意用户可能存在的疑问,比如为何要替代旧的元编程方法,新特性的兼容性等。可能还需要提醒用户不同C++标准版本的支持情况,帮助他们根据项目环境选择合适的特性。 需要检查是否有遗漏的重要特性,如变量模板(C++14)、if constexpr(C++17)、模板的模板参数等。同时,确保示例代码的正确性,比如折叠表达式、概念的使用是否符合语法规范。 总结时,应强调现代C++模板如何提升代码的可维护性、性能,以及编写时的便利性,并建议根据项目需求选择合适的特性,同时注意编译器对C++标准的支持程度。</think>以下是C++模板现代高级用法的分步解析,结合C++11/14/17/20新特性: 1. **变参模板 (Variadic Templates)** ```cpp template<typename... Args> // Args是类型参数包 void log(Args&&... args) { // 完美转发参数包 (std::cout << ... << args) << "\n"; // C++17折叠表达式 } ``` - 应用场景:元组(`std::tuple`)、函数包装器(`std::function`)、格式化输出 - 优势:处理任意数量/类型的参数,替代C风格可变参数 2. **别名模板 (Alias Templates)** ```cpp template<typename T> using Vec = std::vector<T, MyAllocator<T>>; // 带自定义分配器的vector别名 Vec<int> v; // 等价于std::vector<int, MyAllocator<int>> ``` - 对比`typedef`:支持模板参数,更清晰的类型表达 3. **SFINAE与概念(Concepts)** 传统SFINAE: ```cpp template<typename T> auto func(T t) -> std::enable_if_t<std::is_integral_v<T>, void> { /* 仅整数类型可用 */ } ``` C++20概念: ```cpp template<std::integral T> // 使用标准概念约束 void func(T t) { /* ... */ } ``` - 优势:代码更简洁,错误信息更友好 4. **constexpr与编译时计算** ```cpp template<size_t N> constexpr auto factorial() { if constexpr (N <= 1) return 1; // C++17 constexpr if else return N * factorial<N-1>(); } static_assert(factorial<5>() == 120); // 编译时计算验证 ``` 5. **变量模板 (C++14)** ```cpp template<typename T> constexpr T pi = T(3.1415926535897932385L); auto area = pi<double> * r * r; // 精确控制类型精度 ``` 6. **折叠表达式 (C++17)** ```cpp template<typename... Ts> auto sum(Ts... ts) { return (ts + ...); // 展开为ts1 + ts2 + ... + tsN } ``` 对比传统展开方式,减少模板实例化次数 7. **自动返回类型推导 (C++14)** ```cpp template<typename T, typename U> auto add(T t, U u) -> decltype(auto) { // 自动推导返回类型 return t + u; } ``` 8. **惰性求值技术** 表达式模板示例(伪代码): ```cpp Vector a, b, c, d; auto expr = a + b * c - d; // 不立即计算,生成表达式模板 Vector result = expr; // 触发实际计算,优化中间存储 ``` **现代模板编程建议**: 1. 优先使用`constexpr`替代传统模板元编程 2. 用`if constexpr`替代标签分发(tag dispatch) 3. 使用概念(concepts)约束模板参数 4. 结合`auto`和`decltype`简化类型处理 5. 利用折叠表达式处理参数包 6. 使用变量模板替代类模板静态常量 **C++20核心改进**: - 概念(Concepts):显式接口约束 - 约束的auto:`std::ranges::range auto` - 模板lambda:`[]<typename T>(T param) {}` 这些技术广泛应用于: - 高性能计算库(Eigen等) - 序列化框架 - 元编程库(boost.Hana) - 编译时反射系统 使用时需注意: - 编译器对C++标准的支持程度 - 模板实例化带来的编译时间增加 - 错误信息的可读性优化 - 与运行时多态的合理结合
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值