C++ - 模板特化, 非类型模板参数
非类型模板参数
非类型模板参数写法
定义模板时模板的参数可以不是类型, 还可以是常量.
template<class T, size_t N> // N 就是非类型模板参数
class StaticArray
{
public:
size_t size()
{
return N;
}
private:
T _array[N];
}
int main()
{
StaticArray<int, 10> a1;
StaticArray<int, 100> a2;
}
在上面的代码中实现了一个静态的数组类.
这个数组的大小就是由 size_t N 来决定的.
非类型模板参数使用场景
1. 固定大小的数组或容器
非类型模板参数常用于定义具有固定大小的数组或容器, 这样可以在编译时确定数组的大小, 而不需要在运行时动态计算数组的大小, 提高效率。
template <size_t N>
class FixedArray
{
public:
void fill(int value)
{
for (size_t i = 0; i < N; ++i)
{
data[i] = value;
}
}
private:
int data[N];
};
2. 控制函数行为
非类型模板函数可以用来控制函数的行为
如: 通过传递不同的常量值来启用或禁用某些功能
template <class T, bool Enalbe>
class FixedArray
{
public:
void fill(T value)
{
if (Enable)
{
for (size_t i = 0; i < N; ++i)
{
data[i] = value;
}
}
}
private:
T data[N];
};
可能对于某个实例化出来的对象, 就像禁用某一部分的功能, 此时 bool 参数的作用就体现出来了.
3. 优化算法
在算法实现中, 可以根据具体的条件不同, 选择不同的算法.
template <size_t N, size_t M>
class OptimizedAlgorithm
{
// 根据N和M的值选择最优算法
};
模板特化
1. 类模板全特化
全特化是为模板类或函数提供特定类型的完全定制版本.
// 普通模板定义
template <typename T>
class MyClass
{
public:
void func() { /* 通用实现 */ }
};
// 全特化定义
template <>
class MyClass<double>
{
public:
void func() { /* 针对double类型的定制实现 */ }
};
// 普通模板定义
template <typename T, typename T>
class MyTest
{
public:
void func() { /* 通用实现 */ }
};
class A{};
class B{};
// 全特化定义
template <>
class MyClass<A, B>
{
public:
void func() { /* 针对自定义类型 A 和 B 的定制实现 */ }
};
1. 全特化前提: 需要先存在普通模板的定义
2. 全特化, 顾名思义就是将所有的类型参数都特例化
MyTest 中有两个类型模板参数, 在进行特化时, 都要用两个明确的类型来说明
全特化通常用于类模板, 而不是函数模板,
因为函数模板可以通过重载来实现类似全特化的效果.
2. 类模板偏特化
上面讲了全特化, 全特化将所有的类型模板参数都给了明确的类型, 那么可不可以只给一部分参数明确类型.
当然可以, 这就偏特化.
// 普通模板定义
template <typename T, typename U>
class MyClass
{
public:
void func() { /* 通用实现 */ }
};
// 偏特化定义
template <typename U> // 这里为特化的参数名称可以随意取, 名称可以不和原名称相同
class MyClass<double, U>
{
public:
void func() { /* 针对第一个模板参数为double的定制实现 */ }
};
// 这个偏特化定义和上面的定义相同, 不能同时存在
template <typename X>
class MyClass<double, X>
{
public:
void func() { /* 针对第一个模板参数为double的定制实现 */ }
};
注意: 偏特化中保留的模板参数名称可以不和原始模板参数的名称相同
在偏特化定义中, 模板参数名称可以随意,
区别个偏特化主要看 class<参数传递>
template<class T1, class T2, class T3, class T4>
class MyClass
{
public:
MyClass()
{
std::cout << "c0" << std::endl;
}
private:
};
template<class T2, class T3, class T4>
class MyClass<int, T2, T3, T4>
{
public:
MyClass()
{
std::cout << "c1" << std::endl;
}
private:
};
template<class T1, class T3, class T4>
class MyClass<T1, T3, T4, double>
{
public:
MyClass()
{
std::cout << "c2" << std::endl;
}
private:
};
template<class T1, class T4>
class MyClass<T1, double, T4, double>
{
public:
MyClass()
{
std::cout << "c3" << std::endl;
}
private:
};
int main()
{
MyClass<float, float, int, int> c0;
// 类型没有匹配的特例化, 匹配原始模板
MyClass<int, int, int, int> c1;
// 第一个参数类型为 int, 匹配了 MyClass<int, T2, T3, T4>
MyClass<float, int, int, double> c2;
// 最后一个参数类型为 double, 匹配了 MyClass<T1, T3, T4, double>
MyClass<float, double, int, double> c3;
// 第二个和第三个参数类型都是 double, 与MyClass<T1, double, T4, double>更加匹配
// 所以匹配了MyClass<T1, double, T4, double>, 而不是MyClass<T1, T3, T4, double>
}
原文地址:https://blog.csdn.net/m0_74506452/article/details/143924757
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!