C++泛编程

1.auto

auto的主要用途:让编译器自动推断变量的类型

  • 代替冗长复杂的变量声明(函数指针)
  • 在模板中,用于声明依赖模板参数的变量
  • 函数模板依赖模板参数的返回值
  • 用于Lambda表达式中

2.函数模板

1
2
3
4
5
template <typename T>
void func(T &a,T &b)
{

}

注1:可以为类的成员函数创建模板,但不能是虚函数和析构函数。

注2:使用函数模板时,如果自动类型推导,不会发生隐式类型转换,而如果显式指定了函数模板的数据类型,则可以发生隐式类型转换。

编译器使用各种函数的规则:

  • 普通函数>具体化>常规模板

  • 如果希望使用函数模板,可以用空模板参数强制使用函数模板

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <iostream>

    // 普通函数
    void show(int a) {
    std::cout << "普通函数: " << a << std::endl;
    }

    // 函数模板
    template<typename T>
    void show(T a) {
    std::cout << "函数模板: " << a << std::endl;
    }

    int main() {
    int value = 42;

    // 默认情况下,编译器可能优先选择普通函数
    show(value); // 输出: 普通函数: 42

    // 强制使用函数模板
    show<>(value); // 输出: 函数模板: 42

    return 0;
    }
  • 如果函数模板能产生更好的匹配,将优先于普通函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <iostream>

    // 普通函数
    void display(long a) {
    std::cout << "普通函数: " << a << std::endl;
    }

    // 函数模板
    template<typename T>
    void display(T a) {
    std::cout << "函数模板: " << a << std::endl;
    }

    int main() {
    int value = 10;

    // 尽管有一个接受long类型的普通函数,
    // 但函数模板提供了对int类型更直接的匹配。
    display(value); // 输出: 函数模板: 10

    return 0;
    }

函数模板分文件编写:

  • 函数模板只是函数的描述,没有实体,创建函数模板的代码放在头文件中
  • 函数模板具体化有实体,编译原理和普通函数一样,声明放在头文件中,定义放在源文件中。

3.类模板(泛化、全特化、偏特化)

模板泛化

模板泛化是不关心具体的类型,而是提供了通用的实现。

1
2
3
4
5
6
7
8
9
// 泛化的类模板
template <typename T>
class MyClass {
public:
// 泛化的成员函数
void process(T data) {
std::cout << "Generic process: " << data << std::endl;
}
};

全特化

全特化:为某些类型提供更高效的实现

成员函数的全特化

1
2
3
4
5
// 成员函数的特化
template <>
void MyClass<int>::process(int data) {
std::cout << "Specialized process for int: " << data * 2 << std::endl;
}

类模板全特化:

1
2
3
4
5
6
7
8
// 模板的特化
template <>
class MyClass<int> {
public:
void process(int data) {
std::cout << "Specialized implementation for int" << std::endl;
}
};

偏特化

模板偏特化是指在泛化的模板基础上,对其中的某一部分进行特化。

模板参数数量的偏特化:特化部分参数,还存在一部分参数使用通用的模板定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 泛化的类模板,有两个模板参数
template <typename T, typename U>
class Pair {
public:
T first;
U second;
};

// 模板参数数量的偏特化,对第一个模板参数进行特化
template <typename U>
class Pair<int, U> {
public:
int first;
U second;
};

模板参数范围的偏特化:对模板的参数范围进行缩小

  • const 特化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 泛化的类模板
template <typename T>
class MyClass {
public:
void process(T data) {
std::cout << "Generic process: " << data << std::endl;
}
};

// const 特化
template <typename T>
class MyClass<const T> {
public:
void process(const T data) {
std::cout << "Specialized process for const type: " << data << std::endl;
}
};
  • 指针特化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 泛化的类模板
template <typename T>
class MyContainer {
public:
void setValue(T value) {
std::cout << "Generic setValue: " << value << std::endl;
}
};

// 指针特化
template <typename T>
class MyContainer<T*> {
public:
void setValue(T* ptr) {
std::cout << "Specialized setValue for pointers: " << *ptr << std::endl;
}
};
  • 左值引用特化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 泛化的类模板
template <typename T>
class MyReference {
public:
void printValue(T value) {
std::cout << "Generic printValue: " << value << std::endl;
}
};

// 左值引用特化
template <typename T>
class MyReference<T&> {
public:
void printValue(T& ref) {
std::cout << "Specialized printValue for lvalue references: " << ref << std::endl;
}
};
  • 右值引用特化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 泛化的类模板
template <typename T>
class MyRValueReference {
public:
void printValue(T value) {
std::cout << "Generic printValue: " << value << std::endl;
}
};

// 右值引用特化
template <typename T>
class MyRValueReference<T&&> {
public:
void printValue(T&& rvalue) {
std::cout << "Specialized printValue for rvalue references: " << rvalue << std::endl;
}
};

注:函数模板是不能偏特化的,只有类模板可以进行偏特化。函数模板可以不显式指定类型。