第十四章:模板实例化_《C++ Templates》notes

news2025/3/31 19:18:54

模板实例化

      • 核心知识点解析
      • 多选题
      • 设计题
      • 关键点总结

核心知识点解析

两阶段查找(Two-Phase Lookup)
原理
模板在编译时分两个阶段处理:

  1. 第一阶段(定义时):检查模板语法和非依赖名称(Non-dependent Names),此时不依赖模板参数。
  2. 第二阶段(实例化时):检查依赖名称(Dependent Names),并绑定到具体类型。

代码示例

#include <iostream>

template<typename T>
void foo(T t) {
    // 非依赖名称:在编译时检查
    bar(t);  // 第一阶段查找bar(),若未声明则报错
    
    // 依赖名称:在第二阶段实例化时查找
    t.func(); 
}

void bar(int) { std::cout << "bar(int)\n"; }

struct Data {
    void func() const { std::cout << "Data::func()\n"; }
};

int main() {
    foo(42);     // 实例化foo<int>,调用bar(int)和Data::func()
    return 0;
}

测试用例

// 输出:
// bar(int)
// Data::func()

  1. 实例化点(Point of Instantiation, POI)
    原理
    模板实例化的位置由POI决定,通常位于首次使用模板的最近命名空间作用域之后。

代码示例

template<typename T>
void baz() { /* ... */ }

void test() {
    baz<int>();  // 触发baz<int>的实例化
}

// POI位于test()之后,此处可访问baz<int>

测试用例

// 正确:POI在test()之后

  1. 显式实例化(Explicit Instantiation)
    用途
    手动控制模板的实例化位置,避免重复实例化。

代码示例

template<typename T>
T add(T a, T b) { return a + b; }

// 显式实例化int版本
template int add<int>(int, int);

int main() {
    add(1, 2);   // 使用显式实例化的版本
    return 0;
}

测试用例

// 输出:3

  1. 编译期if constexpr(C++17)
    原理
    在编译期根据条件选择代码分支,未使用的代码会被丢弃。

代码示例

template<typename T>
auto get_value(const T& t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}

int main() {
    int x = 5;
    int* p = &x;
    
    std::cout << get_value(x) << "\n";   // 输出5
    std::cout << get_value(p) << "\n";   // 输出5
    return 0;
}

测试用例

// 输出:
// 5
// 5

综合测试程序
以下将所有知识点整合到一个测试程序中:

#include <iostream>
#include <type_traits>

// 两阶段查找示例
template<typename T>
void foo(T t) {
    bar(t);          // 非依赖名称,第一阶段需可见
    t.func();        // 依赖名称,第二阶段实例化时查找
}

void bar(int) { std::cout << "bar(int)\n"; }

struct Data {
    void func() const { std::cout << "Data::func()\n"; }
};

// 显式实例化示例
template<typename T>
T add(T a, T b) { return a + b; }

template int add<int>(int, int);  // 显式实例化int版本

// 编译期if constexpr示例
template<typename T>
auto get_value(const T& t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}

int main() {
    // 测试两阶段查找
    foo(42);     // 调用bar(int)和Data::func()
    
    // 测试显式实例化
    std::cout << add(3, 5) << "\n";  // 输出8
    
    // 测试编译期if constexpr
    int x = 10;
    int* p = &x;
    std::cout << get_value(x) << "\n";   // 输出10
    std::cout << get_value(p) << "\n";   // 输出10
    
    return 0;
}

输出结果

bar(int)
Data::func()
8
10
10

多选题

题目1:模板实例化的基本流程是?
A. 解析模板定义时立即生成代码
B. 使用时按需生成代码(按需实例化)
C. 显式实例化指令触发代码生成
D. 所有模板参数必须显式指定

答案:B, C
详解

  • B 正确:C++ 默认采用按需实例化,仅在用到模板时生成代码。
  • C 正确:通过 template class MyClass<int>; 可显式触发实例化。
  • A 错误:模板定义时不会立即生成代码。
  • D 错误:模板参数可通过推导自动确定。

题目2:两阶段查找(Two-Phase Lookup)的规则是?
A. 非依赖名称在模板定义时解析
B. 依赖名称在模板实例化时解析
C. 所有名称都在实例化时解析
D. ADL 仅在实例化阶段生效

答案:A, B
详解

  • A 正确:非依赖名称(如普通函数名)在模板定义时解析。
  • B 正确:依赖名称(如 T::func)在实例化时结合实参类型解析。
  • C 错误:非依赖名称提前解析。
  • D 错误:ADL 在两阶段均可能生效。

题目3:显式实例化声明(extern template)的作用是?
A. 防止模板在当前翻译单元实例化
B. 强制模板在其他地方实例化
C. 减少编译时间
D. 提升链接效率

答案:A, C
详解

  • A 正确:阻止隐式实例化,避免重复代码生成。
  • C 正确:通过集中实例化减少编译负担。
  • B 错误:仅声明不实现,无法强制实例化位置。
  • D 错误:链接效率取决于实现,非主要目的。

题目4:编译期if constexpr(C++17)与运行期if的关键区别是?
A. 编译期分支可能被完全剔除
B. 运行期if可处理非constexpr条件
C. 编译期if必须满足常量表达式
D. 两者均可用于模板元编程

答案:A, B, C
详解

  • A 正确:未选择的分支代码会被丢弃。
  • B 正确:运行期if无此限制。
  • C 正确:constexpr if条件需在编译期可求值。
  • D 错误:运行期if无法参与模板特化。

题目5:显式实例化与显式特化的区别是?
A. 显式实例化生成通用代码
B. 显式特化为特定模式提供定制实现
C. 显式实例化优先级高于显式特化
D. 显式特化需在命名空间作用域声明

答案:A, B
详解

  • A 正确:template class MyClass<int>; 生成MyClass<int>的代码。
  • B 正确:template<> void MyClass<int>::func() {...} 定制int版本的实现。
  • C 错误:显式特化优先于显式实例化。
  • D 错误:显式特化需在全局或类作用域声明。

题目6:以下哪种情况会导致模板实例化失败?
A. 成员函数模板推导失败
B. 构造函数默认参数未定义
C. 虚函数表生成时依赖未实例化的类型
D. 静态成员变量未显式初始化

答案:A, B, C
详解

  • A 正确:成员函数模板推导失败会导致实例化中止。
  • B 正确:构造函数默认参数若依赖未实例化的类型会失败。
  • C 正确:虚表生成需要完整类型信息。
  • D 错误:静态成员可在类外延迟初始化。

题目7:类模板成员的显式实例化方式是?
A. template void MyClass<int>::func();
B. template MyClass<int>::func();
C. extern template void MyClass<int>::func();
D. template<> void MyClass<int>::func();

答案:A
详解

  • A 正确:显式实例化成员函数的语法。
  • B 错误:缺少template关键字。
  • C 错误:extern用于声明而非定义。
  • D 错误:这是显式特化的语法。

题目8:编译期if constexpr的典型应用场景是?
A. 实现类型萃取(Type Traits)
B. 条件编译不同代码路径
C. 优化递归模板展开
D. 替代宏定义

答案:A, B, C
详解

  • A 正确:通过条件判断筛选类型特性。
  • B 正确:根据常量条件选择执行路径。
  • C 正确:避免无效分支的代码膨胀。
  • D 错误:constexpr if无法完全替代宏的语义。

题目9:模板实例化的存储优化技术包括?
A. 链接器去重(Linker Deduplication)
B. 内联展开(Inlining)
C. 空基类优化(EBO)
D. 全局变量合并

答案:A, B
详解

  • A 正确:链接器消除重复实例化的代码。
  • B 正确:小函数可能被内联以避免实例化。
  • C 错误:EBO与模板实例化无关。
  • D 错误:全局变量合并不适用于模板。

题目10:以下代码的输出是?

template<typename T> void foo(T) { cout << "T" << endl; }
template<> void foo<int>(int) { cout << "int" << endl; }
extern template void foo<double>(double);

int main() {
    foo(1);    // A
    foo(1.0);  // B
    foo('c');  // C
}

A. int
B. T
C. T

答案:A. int, B. T, C. T
详解

  • A 调用显式特化版本。
  • B 未显式实例化double,按需实例化通用版本。
  • C 字符字面量推导为char,调用通用版本。

设计题

题目1:实现一个线程安全的单例模式,要求支持任意类型T,并利用显式实例化优化性能。

#include <iostream>
#include <mutex>

template<typename T>
class Singleton {
private:
    static T* instance;
    static std::once_flag flag;
    
    Singleton() = default;
    ~Singleton() = default;
    
public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    
    static T& getInstance() {
        std::call_once(flag, []{
            instance = new T();
        });
        return *instance;
    }
};

// 显式实例化常用类型以优化性能
template<> Singleton<int>::instance = nullptr;
template<> std::once_flag Singleton<int>::flag;

int main() {
    Singleton<int>& si = Singleton<int>::getInstance();
    Singleton<std::string>& ss = Singleton<std::string>::getInstance();
    return 0;
}

题目2:编写一个模板元函数is_pointer_v,检测类型是否为指针,并利用编译期if constexpr优化性能。

#include <iostream>
#include <type_traits>

template<typename T>
constexpr bool is_pointer_v = false;

template<typename T>
constexpr bool is_pointer_v<T*> = true;

template<typename T>
void checkPointer(T val) {
    if constexpr (is_pointer_v<T>) {
        std::cout << "Pointer type" << std::endl;
    } else {
        std::cout << "Non-pointer type" << std::endl;
    }
}

int main() {
    int a;
    int* p = &a;
    checkPointer(a);  // 输出 Non-pointer type
    checkPointer(p);  // 输出 Pointer type
    return 0;
}

题目3:实现一个泛型缓存类Cache,支持通过键值快速访问对象,利用显式实例化减少模板代码膨胀。

#include <unordered_map>
#include <string>

template<typename Key, typename Value>
class Cache {
private:
    std::unordered_map<Key, Value> storage;
    
public:
    void set(const Key& key, const Value& value) {
        storage[key] = value;
    }
    
    Value get(const Key& key) {
        return storage[key];
    }
};

// 显式实例化常用组合
template class Cache<std::string, int>;
template class Cache<int, std::string>;

int main() {
    Cache<std::string, int> intCache;
    intCache.set("age", 25);
    std::cout << intCache.get("age") << std::endl;  // 输出 25
    
    Cache<int, std::string> strCache;
    strCache.set(1, "one");
    std::cout << strCache.get(1) << std::endl;  // 输出 one
    return 0;
}

题目4:设计一个支持多种序列化协议的模板类Serializer,利用显式实例化适配不同协议。

#include <iostream>
#include <string>

enum class Protocol { JSON, XML };

template<Protocol P>
class Serializer {
public:
    static std::string serialize(int value) {
        if constexpr (P == Protocol::JSON) {
            return "{\"value\":" + std::to_string(value) + "}";
        } else {
            return "<value>" + std::to_string(value) + "</value>";
        }
    }
};

// 显式实例化常用协议
template class Serializer<Protocol::JSON>;
template class Serializer<Protocol::XML>;

int main() {
    std::cout << Serializer<Protocol::JSON>::serialize(42) << std::endl;  // 输出 {"value":42}
    std::cout << Serializer<Protocol::XML>::serialize(42) << std::endl;   // 输出 <value>42</value>
    return 0;
}

题目5:实现一个类型萃取工具TypeTraits,利用编译期if constexpr简化类型判断逻辑。

#include <iostream>
#include <type_traits>

template<typename T>
struct TypeTraits {
    static constexpr bool is_pointer = false;
    static constexpr bool is_reference = false;
};

template<typename T>
struct TypeTraits<T*> {
    static constexpr bool is_pointer = true;
};

template<typename T>
struct TypeTraits<T&> {
    static constexpr bool is_reference = true;
};

template<typename T>
void analyzeType(const T& value) {
    if constexpr (TypeTraits<T>::is_pointer) {
        std::cout << "Pointer type" << std::endl;
    } else if constexpr (TypeTraits<T>::is_reference) {
        std::cout << "Reference type" << std::endl;
    } else {
        std::cout << "Value type" << std::endl;
    }
}

int main() {
    int a = 5;
    int* p = &a;
    int& r = a;
    
    analyzeType(a);  // 输出 Value type
    analyzeType(p);  // 输出 Pointer type
    analyzeType(r);  // 输出 Reference type
    return 0;
}

代码测试说明

  1. 编译命令:使用支持C++17的编译器(如GCC 7+、Clang 5+):
    g++ -std=c++17 -o test test.cpp && ./test
    
  2. 测试要点
    • 每个设计题的main函数均包含测试用例。
    • 多选题答案需结合书中第十四章的实例化机制、两阶段查找规则等知识点验证。

关键点总结

  1. 两阶段查找:确保模板定义时非依赖名称可见,依赖名称在实例化时解析。
  2. 显式实例化:通过template关键字手动实例化,减少编译开销。
  3. if constexpr:编译期分支选择,优化生成的代码。

通过以上示例和测试,可以深入理解C++模板实例化的机制和优化技巧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

循环查询指定服务器开放端口(Python)

循环查询指定服务器开放端口列表 # Time : 2025/3/22 # Author : cookie # Desc :import socket import concurrent.futures from datetime import datetime# 设置目标IP和端口范围 target_ip input("请输入目标IP地址: ") start_port int(input("请输入…

【STM32】第一个工程的创建

目录 1、获取 KEIL5 安装包2、开始安装 KEIL52.1、 激活2.2、安装DFP库 3、工程创建4、搭建框架5、开始编写代码 1、获取 KEIL5 安装包 要想获得 KEIL5 的安装包&#xff0c;在百度里面搜索“KEIL5 下载”即可找到很多网友提供的下载文件&#xff0c;或者到 KEIL 的官网下载&a…

SpringBoot+策略模式+枚举类,优雅消除if-else

需求分析 公司做物联网系统的&#xff0c;使用nettry进行设备连接&#xff0c;对设备进行数据采集&#xff0c;根据设备的协议对数据进行解析&#xff0c;解析完成之后存放数据库&#xff0c;但是不同厂家的设备协议不同。公司系统使用了使用了函数式编程的去写了一个解析类&am…

前端框架学习路径与注意事项

学习前端框架是一个系统化的过程&#xff0c;需要结合理论、实践和工具链的综合掌握。以下是学习路径的关键方面和注意事项&#xff1a; 一、学习路径的核心方面 1. 基础概念与核心思想 组件化开发&#xff1a;理解组件的作用&#xff08;复用性、隔离性&#xff09;、组件通信…

Linux驱动开发-①platform平台②MISC字符驱动框架③input框架

Linux驱动开发-①platform平台②MISC字符驱动框架③input框架 一&#xff0c;platform1.1 platform框架&#xff08;设备树下&#xff09;1.2 platform框架&#xff08;配置设备函数&#xff09; 二&#xff0c;MISC字符驱动框架三&#xff0c;input框架 一&#xff0c;platfor…

【mysql】唯一性约束unique

文章目录 唯一性约束 1. 作用2. 关键字3. 特点4. 添加唯一约束5. 关于复合唯一约束 唯一性约束 1. 作用 用来限制某个字段/某列的值不能重复。 2. 关键字 UNIQUE3. 特点 同一个表可以有多个唯一约束。唯一约束可以是某一个列的值唯一&#xff0c;也可以多个列组合的值唯…

常见中间件漏洞:Jboss篇

CVE-2015-7501 环境搭建 cd vulhub-master/jboss/JMXInvokerServlet-deserialization docker-compose up -d 过程 访问网址&#xff0c;存在页面说明接口存在且存在反序列化漏洞 http://8.130.17.222:8080/invoker/JMXInvokerServlet 2.下载 ysoserial ⼯具进⾏漏洞利⽤…

2025年优化算法:龙卷风优化算法(Tornado optimizer with Coriolis force,TOC)

龙卷风优化算法&#xff08;Tornado optimizer with Coriolis force&#xff09;是发表在中科院二区期刊“ARTIFICIAL INTELLIGENCE REVIEW”&#xff08;IF&#xff1a;11.7&#xff09;的2025年智能优化算法 01.引言 当自然界的狂暴之力&#xff0c;化身数字世界的智慧引擎&…

3.24-3 接口测试断言

一.postman 断言 1.断言再test中 #状态码是否等于200 tests["Status code is 200"] responseCode.code 200; #断言响应时间小于200ms tests["Response time is less than 200ms"] responseTime < 200; #断言响应体包含内容 tests["Body…

DeepSeek面试——模型架构和主要创新点

本文将介绍DeepSeek的模型架构多头潜在注意力&#xff08;MLA&#xff09;技术&#xff0c;混合专家&#xff08;MoE&#xff09;架构&#xff0c; 无辅助损失负载均衡技术&#xff0c;多Token 预测&#xff08;MTP&#xff09;策略。 一、模型架构 DeepSeek-R1的基本架构沿用…

Python----计算机视觉处理(Opencv:图像亮度变换)

一、图像亮度变换 亮度调整&#xff1a;图像像素强度整体变高或者变低。 对比度调整&#xff1a;图像暗处像素强度变低&#xff0c;图像亮处像素强度变高&#xff0c;从而拉大中间某个区域范围的显示精 度。 A&#xff1a;原图 …

无人机动平衡-如何在螺旋桨上添加或移除材料

平衡无人机螺旋桨是一项精细的工作&#xff0c;直接影响飞行稳定性和组件寿命。不同的方法适用于不同的情况&#xff0c;螺旋桨的材料和尺寸以及所需调整的幅度都会影响选择的方法。 本文将深入探讨添加如胶水和胶带等材料的方法&#xff0c;以及通过打磨和修剪来移除质量的方…

基于python的租房网站-房屋出租租赁系统(python+django+vue)源码+运行步骤

该项目是基于python/django/vue开发的房屋租赁系统/租房平台&#xff0c;作为本学期的课程作业作品。欢迎大家提出宝贵建议。给师弟开发的课程作业&#xff0c;技术学习可以留言哦 功能介绍 平台采用B/S结构&#xff0c;后端采用主流的PythonDjango进行开发&#xff0c;前端采…

涨薪技术|k8s设计原理

01k8s介绍 Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化 工作负载和服务&#xff0c;有助于实现声明性配置和自动化。它有一个庞大、快速增长的生态系统。Kubernetes 服务、支持和工具广泛可用。Kubernetes 这个名字起源于希腊语&#xff0c;意思是舵…

基于FPGA的16QAM+帧同步系统verilog开发,包含testbench,高斯信道,误码统计,可设置SNR

目录 1.算法仿真效果 2.算法涉及理论知识概要 2.1 16QAM调制解调原理 2.2 帧同步 3.Verilog核心程序 4.完整算法代码文件获得 1.算法仿真效果 vivado2019.2仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 设置SNR12db 将FPGA数据导入到MATLAB显…

QuecPython 外设接口之GPIO应用指南

基础知识 了解GPIO基础知识更有益于我们使用它。 框图 GPIO&#xff08;通用输入输出&#xff09;是指一种通用的数字输入/输出接口&#xff0c;用于与外部电子元件或设备进行通信。它通常存在于微处理器、微控制器和其他嵌入式系统中。 物理电路结构如下图所示&#xff1a…

Spring Boot 整合 Nacos 注册中心终极指南

在微服务架构中&#xff0c;配置管理和动态路由是核心需求。Nacos 作为阿里巴巴开源的动态服务发现、配置管理和服务管理平台&#xff0c;能够帮助开发者实现配置热更新、多环境共享配置以及动态路由管理。本文将结合 Spring Boot 和 Spring Cloud Gateway&#xff0c;手把手教…

SQLServer列转行操作及union all用法

1.创建测试表及数据sql如下 create table ScoresTable( Name varchar(50), ChineseScore int, MathScore int ) insert into ScoresTable values(小张,90,95) insert into ScoresTable values(小王,98,99) 2.表中查询结果如下 3.现需列转行显示&#xff0c;每行显示 姓名…

【GL010】C++

1.C中的const关键字有哪些用法&#xff1f; 1.修饰变量&#xff1a;表示变量的值不可修改。 const int a 10; 2.修饰指针&#xff1a; const int* p&#xff1a; // 指针指向的内容不可修改。 int* const p&#xff1a; // 指针本身不可修改。 const int* const…

(Arxiv-2025)MagicDistillation:用于大规模人像少步合成的弱到强视频蒸馏

MagicDistillation&#xff1a;用于大规模人像少步合成的弱到强视频蒸馏 paper是HKUST发布在Arxiv 2025的工作 paper title&#xff1a;MagicDistillation: Weak-to-Strong Video Distillation for Large-Scale Portrait Few-Step Synthesis Project page&#xff1a;地址 Abst…