自学内容网 自学内容网

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)!