普通类的成员函数模板
不管是普通类还是类模板,它的成员函数可以是一个函数模板,称为“成员函数模板”,不可以是虚函数,否则编译器会报错。
#include <iostream>
#include "myvector.hpp"
#include "test.h"
using namespace std;
class A
{
public:
template<typename T>
void myft(T temp) //成员函数模板
{
cout << temp <<endl;
}
};
int main()
{
//普通类的成员函数模板
//不管是普通类,还是类模板,它的成员函数可以是一个函数模板,称为“成员函数模板”,不可以是虚函数
A a;
a.myft(3); //执行这句话的时候,才会实例化这个模板。
cout << "Hello world!" << endl;
return 0;
}
类模板的成员函数模板
#include <iostream>
#include "myvector.hpp"
#include "test.h"
using namespace std;
template<typename C>
class A
{
public:
template <typename T2>
A(T2 v1, T2 v2);
// {
//构造函数我们也引入自己的模板,和整个类的模板C没关系
//}
template<typename T>
void myft(T temp) //成员函数模板
{
cout << temp <<endl;
}
void myfunc() //普通成员函数
{
}
C m_ic;
};
template <typename C> //先跟类的模板参数列表
template <typename T2> //再跟构造函数自己的模板参数列表
A<C>::A(T2 v1, T2 v2)
{
cout << v1 <<" "<<v2<< endl;
}
int main()
{
//类模板的成员函数模板
//类模板的模板参数必须用<>指定, 成员函数模板(函数模板)的参数都可以推断。
A<float> a(1 , 2);
A<float> a2(1.2 , 2.2);
//类模板的成员函数(包括普通成员函数、成员函数)只有为程序所用,才进行实例化
//如果某函数从未使用,则不会实例化该成员函数。
a.myft(9); //调用的时候才会实例化
cout << "Hello world!" << endl;
return 0;
}
类模板的成员函数(包括普通成员函数、成员函数模板)只有为程序所用时(代码中出现了)才会实例化。如果某函数从未使用则不会实例化(.obj 中生成代码)该成员函数。
(也就是说如果代码中没有调用到类成员函数时,编译器编译生成的 .obj 文件中是没有这个成员函数代码的)
模板显式实例化,模板声明
模板实例化,每个cpp文件都会实例化自己的模板。
为了防止多个.cpp文件中都实例化相同的类模板,所以C++11提出了一个解决方法,我们称为"显式实例化";通过"显式实例化"避免生成多个相同类模板实例的开销。
模板的实例化定义只有一个,模板的实例化声明可以有多个。
ca.h
#pragma once
#ifndef __CAH__
#define __CAH__
#include <iostream>
// 类模板的参数
template <typename C>
class A // 普通类
{
public:
// 构造函数模板
// 与整个类的模板没有关系
template <typename T2>
A(T2 v1, T2 v2);
template <typename T>
// 成员函数模板
void myft(T tmpt)
{
cout << tmpt << endl;
}
// 普通成员函数
template <typename T2>
void myfunc(T2 v1, T2 v2);
C m_ic; // 类模板变量
};
// 先跟类的模板参数列表
template <typename C>
// 再跟构造函数自己的模板参数列表
template <typename T2>
A<C>::A(T2 v1, T2 v2)
{
cout << v1 << v2 << endl;
}
template <typename T>
void mfunc123(T v1, T v2)
{
cout << v1 + v2 << endl;
}
#endif
ca.cpp
#include "ca.h"
using namespace std;
// 显式实例化手段中的实例化定义,这种实例化只需在一个.cpp
// 文件中写就可以
// 编译器遇到这段代码就直接实例化一个A<float>
template A<float>;
void mfunc()
{
A<float> a(1, 2);
}
// 先跟类的模板参数列表
template <typename C>
// 再跟构造函数自己的模板参数列表
template <typename T2>
void A<C>::myfunc(T2 v1, T2 v2)
{
}
// 编译器会为其生成代码
template void mfunc123(int v1, int v2);
main.cpp
#include <iostream>
#include "ca.h"
using namespace std;
// 显式实例化手段中的"实例化声明"
// 其他所有.cpp文件用到这个类型的话都这么写
// 在一个文件中实例化,其他文件全部为声明
// extern template A<float>;
// extern作用:不会在在本文件中生成一个extern后面所表示的模板的实例化代码
// extern目的:告诉编译器,在其他的源文件(.cpp)中已经有了一个改该模板的实例化版本了。
extern template A<float>;
// 显式声明函数模板
extern template void mfunc123(int v1, int v2);
int main()
{
A<float> a(1, 2);
A<float> b(1.1, 2.2);
return 0;
}
只需要在一个 .cpp 文件中做实例化定义,在其他 .cpp 文件中做实例化声明
extern template A<float>
extern作用:不会在本文件中生成一个 extern后边所表示的模板的实例化版本。
extern目的:高作编译器,在其他的源 .cpp文件 中已经有了一个该模板的实例化版本了。
(extern实际上可能没有达到我们预期系统所能达到的效果,还是会实例化类模板)
模板的实例化定义只有一个,实例化声明可以有多个。
总结:
vs2017不太推荐这个特色写法。