C++模板特化,Concept,typename,dependent name

typename T,表示T为类型,而不是变量
那,T::A是什么?T可以是我们自己写的类,那T::A就是成员变量或成员函数,另外,T::A还可以是类型,T内定义的类型
所以,编译器需要区分,T::A到底是什么
这个问题又叫做 dependent name,依赖名
A是依赖于T的,而T是模板,所以才有这样的问题
所以,有时候才会看到在使用T::A定义变量时,前面加上了一个typename关键字

要从模板说起
template,T就是一个模板,可以是int,double,float之类的
但T是不是还可能是指针类,引用类?

//接收任意参数
template<typename T>
class A {};

//上面模板类的偏特化,接收的是指针类型,但可以是int double float等多个类型的指针,是个子集
template<typename T>
class A<T *> {};

//另一个偏特化例子
template<typename T>
class A<const T> {};

//全特化
template<>
class A<int> {}

有时候,对于某些类别,比如指针,需要做特殊处理,告诉模板,遇到指针按我写的特别处理,这叫模板特化,与实例化不同,模板遇到不同类别如int,double会实例化

这只是一元模板的情况下,实际上,可能会有多元模板,下面是一个二元模板的例子,模板类,模板函数的偏特化好像有些问题

//模板,接收全集R
template <typename T, typename Allocator_T>
class MyVector {
public:
    MyVector() {
        std::cout << "Normal version." << std::endl;
    }
};

//偏特化,第二个参数特殊指定
template <typename T>//声明模板时第二元省略
class MyVector<T, DefaultAllocator> {//但这里要对第二元进行指定
public:
    MyVector() {
        std::cout << "Partial version." << std::endl;
    }
};

从模板可以接受的类型角度来看,和多元函数一样,可以有多个维度
将模板可以接受的所有类型(组合)看做全集R
模板全特化就是,多元模板每一维都指定,为坐标空间的一个点
模板的偏特化是指对R中的子集(部分类别)进行特殊处理,可以是某些元上偏特化,和偏导数有点像哈
匹配的规则就是,越特化,越优先匹配
全特化>偏特化>R

在C++20版本特性中,有一个Concept就是为了此类问题而生的

template <typename A, typename B>
void f(A a, B b) {
    std::cout << "Normal version." << std::endl;
}

template <typename A, typename B>
requires std::integral<B>//integral意思为完整的,整数
void f(A a, B b) {
    std::cout << "Partial version." << std::endl;
}

使用requres对模板进行了偏特化,要求B为整数类型

接下来看看模板偏特化的一个作用,提取类别信息,const类型的变量就会匹配到const版本的特化模板实现,从而去除const

#include <iostream>
#include <type_traits> //is_same

template<typename T>
struct remove_const {
    using type = T;
};

//const变量特化
template<typename T>
struct remove_const<const T> {
    using type = T;//type为不带const的T
};

int main() {
    int a = 1;
    const int b = 2;
    remove_const<decltype(a)>::type aa = 3;
    remove_const<decltype(b)>::type bb = 4;
    std::cout << std::is_same<decltype(aa), int>::value << std::endl;
    std::cout << std::is_same<decltype(bb), int>::value << std::endl;
    return 0;
}
posted @ 2023-03-19 10:57  ecnu_lxz  阅读(103)  评论(0编辑  收藏  举报