类模版的实例化instantiation

本文探讨了C++中模板类的实例化过程,包括成员声明与定义的实例化时机、默认参数实例化行为及匿名联合的编译特性。强调了虚拟函数定义的重要性,并通过实例展示了参数匹配的过程。

类模版的实例化instantiation

 

When a class template is implicitly instantiated, each declaration of its members is instantiated as well, but the corresponding definitions are not.

#include "stdafx.h"

 

template <typename T>

class Safe {

};

 

template <int N>

class Danger {

public:

        typedef char Block[N];  // would fail for N<=0

};

 

template <typename T, int N>

class Tricky {

public:

        virtual ~Tricky() {

        }

        void no_body_here(Safe<T> = 3);

        void inclass() {

                Danger<N> no_boom_yet;

        }

         void error() { Danger<N> boom; }

         //void unsafe(T (*p)[N]);

        T operator->();

        // virtual Safe<T> suspect();

        struct Nested {

                Danger<N> pfew;

        };

        union {  // anonymous union

                int align;

                Safe<T> anonymous;

                //Danger<N> pfew;

        };

};

int main()

{

        Tricky<int, -1> ab;

        //ab.error();

        system("pause");

}

 

显然N为负数的时候是非法的,但是“lazy instantiation”只对函数申明中的N实例化(参数),函数体中的N在程序调用该函数的时候才去实例化

 

所以unsafe函数如果不注释,是无法编译的,而error函数只要不去调用,仍然可以通过编译

Default function call arguments are considered separately when instantiating templates. Specifically, they are not instantiated unless there is a call to that function (or member function) that actually makes use of the default argument. If, on the other hand, that function is called with explicit arguments that override the default, then the default arguments are not instantiated.

. Similarly, had the member anonymous been declared with type Danger<N> instead of Safe<T>, an error would be triggered because type Danger<0> cannot be completed

匿名Union会被编译

 

In practice, the definitions of virtual members should also be provided; otherwise, linker errors are likely to occur. This may have been a problem if we had uncommented the declaration of the virtual member suspect() for which no definition was provided.

虚函数必须提供函数定义

#include <iostream>
using namespace std;


template<typename T>
void g(T& t)
{
  t = 30;
  cout<<t<<endl;
}
void main()
{
 //g(10);
}

 

编译通过,如果去掉注释,不过

 

#include <iostream>
using namespace std;

template<typename T>
void f(T t)
{
  t = 5;
  cout<< t * 3 <<endl;
}
template<typename T>
void g(T& t)
{
  t = 11;
  cout<<t*2<<endl;
}
void main()
{
 
 int const seven = 7; 
 
 f(seven);  // OK !nonreference parameter: T is int
 g(seven);  // error C2166: l-value specifies const object
}

 

由于g函数参数为reference,所以 const保留 ?

We still need to explore how argument-parameter matching proceeds. We describe it in terms of matching a type A (derived from the argument type) to a parameterized type P (derived from the parameter declaration). If the parameter is declared with a reference declarator, P is taken to be the type referenced, and A is the type of the argument. Otherwise, however, P is the declared parameter type, and A is obtained from the type of the argument by decaying [2] array and function types to pointer types, ignoring top-level const and volatile qualifiers.

<think>好的,用户想了解C++模板实例化方法。根据之前的对话,用户之前询问过线程安全的拷贝构造函数,现在转向模板实例化。需要结合用户提供的引用内容,特别是引用1到3,来组织回答。 首先,用户的引用1提到了隐式实例化和显式实例化两种方法。引用2和3分别给出了模板继承和实例化的例子。需要确保覆盖这两种实例化方法,并给出代码示例。 用户的问题是关于模板实例化的方法,所以需要分点解释隐式和显式实例化,可能还要提到部分特例化或完全特例化。要注意使用用户提供的引用中的例子,比如引用2中的Base和Derived,引用3中的array<int>的例子。 同时,用户之前的回答中提到了线程安全,但这次问题不涉及,所以不需要涉及多线程内容。需要保持回答结构清晰,符合用户要求的系统指令,比如行内公式用$符号,独立公式用$$,正确使用LaTeX语法,中文回答,生成相关问题等。 需要检查是否有遗漏的实例化方法,比如显式实例化的语法、何时使用显式实例化,以及可能出现的常见问题和注意事项,比如模板定义可见性、重复实例化错误等。另外,用户提供的引用中有关于派生模板的例子,可能需要提到继承时的实例化注意事项。 最后,生成的相关问题需要与模板实例化相关,比如隐式和显式的区别、特例化的应用场景、解决链接错误的方法等。确保引用标识正确,比如引用[^1][^2][^3]来自用户提供的资料。</think>以下是对C++模板实例化方法的系统说明,结合模板实例化的核心机制与工程实践: --- ### 一、模板实例化基本原理 模板实例化是将通用模板转换为具体的过程,其核心是**二次编译机制**: 1. 首次编译:检查模板语法(不生成机器码) 2. 实例化编译:根据具体型生成二进制代码 例如: ```cpp template<typename T> class Vector { // 模板定义 private: T* elements; int size; public: void push_back(const T& item); }; Vector<int> v1; // 实例化int版本 Vector<double> v2; // 实例化double版本 ``` 此时编译器会生成`Vector<int>`和`Vector<double>`两个独立[^3] --- ### 二、实例化方法分 #### 1. 隐式实例化(Implicit Instantiation) 通过对象声明自动触发,是最常用方式: ```cpp template<typename T> class Matrix { public: Matrix(int rows, int cols) : data(new T[rows*cols]) {} private: T* data; }; Matrix<float> m(3, 4); // 隐式实例化float版本[^1] ``` 特性: - 按需生成代码(未使用的成员函数不实例化) - 可能导致编译时间膨胀(多次相同实例化) - 必须可见模板完整定义(头文件中定义) #### 2. 显式实例化(Explicit Instantiation) 手动指定实例化型,控制代码生成: ```cpp // 模板声明 template<typename T> class CircularBuffer; // 显式实例化指令 template class CircularBuffer<double>; // 生成double版本[^2] // 使用时不触发编译期生成 CircularBuffer<double> buf; // 直接使用预生成代码 ``` 优势: - 减少编译时间(避免重复实例化) - 控制符号可见性(DLL/SO开发常用) - 强制检查模板有效性(提前发现错误) #### 3. 特化实例化(Specialization) ##### (1) 完全特化(Full Specialization) ```cpp template<> class Vector<bool> { // 针对bool型的特化版本 private: uint8_t* packed_data; // 使用位压缩存储 public: void flip_all() { /* 位操作实现 */ } }; ``` ##### (2) 部分特化(Partial Specialization) ```cpp template<typename T> class Vector<T*> { // 针对指针型的特化 public: void clear() { for(int i=0; i<size; ++i) delete elements[i]; // 深度释放指针 } }; ``` --- ### 三、实例化控制技巧 #### 1. 延迟实例化(Lazy Instantiation) ```cpp template<typename T> class Logger { public: void log(const T& msg) { static_assert(std::is_copy_constructible_v<T>, // 仅在调用时检查 "T must be copy constructible"); // ... } }; Logger<std::thread> logger; // 合法(未调用log方法时不实例化) ``` #### 2. 显式抑制实例化 ```cpp extern template class Matrix<std::string>; // 声明但不实例化[^1] ``` #### 3. 继承链中的实例化 ```cpp template<typename T> class Base { public: virtual void serialize(T) const; }; template<typename T> class Derived : public Base<T> { // 派生模板 public: void serialize(T) const override; }; // 显式实例化会触发派生实例化 template class Base<int>; // 同时生成Derived<int>[^2] ``` --- ### 四、工程实践要点 1. **分离编译问题** 模板定义必须放在头文件中(或使用显式实例化) 2. **符号重复解决方案** ```cpp // 在头文件中声明 extern template class Stack<double>; // 在.cpp文件中定义 template class Stack<double>; ``` 3. **型推导辅助** ```cpp template<typename T=int> // 默认型参数 class Buffer { /*...*/ }; Buffer<> buf; // 自动实例化为Buffer<int> ``` 4. **C++17特性`if constexpr`** ```cpp template<typename T> class SmartPtr { public: void reset() { if constexpr(std::is_array_v<T>) { delete[] ptr; // 仅对数组型生效 } else { delete ptr; } } }; ``` --- ### 五、调试与优化 1. 查看实例化结果(GCC): ```bash g++ -fdump-class-hierarchy -c template_use.cpp ``` 2. 减少编译时间: - 使用显式实例化集中管理 - 预编译头文件(PCH) - 外部模板声明(C++11) 3. 检测未实例化错误: ```cpp static_assert(sizeof(MyTemplate<char>) > 0, "Template instantiation failed"); ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值