基础应用
1. template
1.1 作用
- 定义 泛型:支持类、函数、变量等的通用化编程
- 编译器会在实例化时生成对应的类型版本(模板展开)
- 支持 函数模板、类模板、模板特化、模板参数推导
1.2 基本语法
template <typename T>
T add(T a, T b) {
return a + b;
}
2. implicit
(隐式转换)
C++ 没有单独的
implicit
关键字(这是 C# 和 Swift 的关键字),但 C++ 中隐式转换的机制与构造函数、转换运算符相关。
- 隐式构造函数:只有一个参数的构造函数可以被编译器自动调用进行类型转换
- 隐式类型转换运算符:
operator T()
形式 - 可以用
explicit
关键字禁止隐式转换
3. explicit
3.1 作用
- 修饰构造函数或转换运算符
- 防止编译器进行 隐式类型转换,要求必须显式调用
3.2 常见场景
- 防止单参数构造函数被隐式调用
- 防止类型转换运算符在不期望的地方被自动触发
4. 应用示例
示例 1:模板函数
#include <iostream>
template <typename T>
T multiply(T a, T b) { return a * b; }
int main() {
std::cout << multiply(3, 4) << "\n"; // int
std::cout << multiply(3.5, 2.0) << "\n"; // double
}
示例 2:类模板
#include <iostream>
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T get() const { return value; }
};
int main() {
Box<int> bi(42);
Box<std::string> bs("Hello");
std::cout << bi.get() << ", " << bs.get() << "\n";
}
示例 3:模板特化
#include <iostream>
template <typename T>
void printType(T) { std::cout << "Generic\n"; }
template <>
void printType<int>(int) { std::cout << "Int type\n"; }
int main() {
printType(1); // 特化版本
printType(3.14); // 泛型版本
}
示例 4:模板 + 默认参数
#include <iostream>
template <typename T = int>
T add(T a, T b) { return a + b; }
int main() {
std::cout << add(1, 2) << "\n"; // 使用默认模板参数
}
示例 5:隐式转换构造函数
#include <iostream>
class Meter {
double m;
public:
Meter(double m) : m(m) {} // 允许隐式转换
double get() const { return m; }
};
void print(Meter m) { std::cout << m.get() << " meters\n"; }
int main() {
print(5.0); // double -> Meter 隐式转换
}
示例 6:explicit
禁止隐式转换
#include <iostream>
class Meter {
double m;
public:
explicit Meter(double m) : m(m) {} // 禁止隐式
double get() const { return m; }
};
void print(Meter m) { std::cout << m.get() << " meters\n"; }
int main() {
// print(5.0); // 编译错误
print(Meter(5.0)); // 必须显式构造
}
示例 7:隐式类型转换运算符
#include <iostream>
class Fraction {
double val;
public:
Fraction(int num, int den) : val(double(num) / den) {}
operator double() const { return val; } // 隐式转换为 double
};
int main() {
Fraction f(3, 4);
double d = f; // 隐式转换
std::cout << d << "\n";
}
示例 8:explicit
转换运算符
#include <iostream>
class Fraction {
double val;
public:
Fraction(int num, int den) : val(double(num) / den) {}
explicit operator double() const { return val; } // 禁止隐式
};
int main() {
Fraction f(3, 4);
// double d = f; // 编译错误
double d = static_cast<double>(f); // 必须显式
std::cout << d << "\n";
}
示例 9:模板与隐式转换结合
#include <iostream>
template <typename T>
void print(T t) { std::cout << t << "\n"; }
class Meter {
double m;
public:
Meter(double m) : m(m) {}
double get() const { return m; }
friend std::ostream& operator<<(std::ostream& os, const Meter& mt) {
return os << mt.m << "m";
}
};
int main() {
print(Meter(3.5)); // 模板参数推导
print(42); // int 版本
}
示例 10:模板 + explicit
构造函数
#include <iostream>
template <typename T>
class Wrapper {
T value;
public:
explicit Wrapper(T v) : value(v) {}
T get() const { return value; }
};
int main() {
// Wrapper<int> w = 5; // 编译错误(禁止隐式转换)
Wrapper<int> w(5); // 必须显式构造
std::cout << w.get() << "\n";
}
总结对比表
关键字 | 功能 | 主要用途 | 风险点 |
---|---|---|---|
template |
泛型编程 | 代码复用、类型无关实现 | 模板膨胀、编译时间长 |
隐式转换(无关键字) | 自动类型匹配 | 提高代码简洁性 | 可能产生意外转换 |
explicit |
禁止隐式转换 | 保证类型安全 | 调用更繁琐但更明确 |
高级应用
一、template
高级应用
1. 模板特化与偏特化(Partial Specialization)
在泛型编程中,可以针对某些类型单独优化实现。
#include <iostream>
#include <string>
using namespace std;
template <typename T>
struct Printer {
static void print(const T& value) {
cout << "Generic: " << value << endl;
}
};
// 针对 string 偏特化
template <>
struct Printer<string> {
static void print(const string& value) {
cout << "String: \"" << value << "\"" << endl;
}
};
int main() {
Printer<int>::print(42);
Printer<string>::print("Hello");
}
应用场景:针对不同传感器数据类型提供专门优化实现。
2. SFINAE(Substitution Failure Is Not An Error)
控制模板匹配,使得编译器在类型不满足条件时忽略该模板版本。
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
auto printIfIntegral(T value) -> typename enable_if<is_integral<T>::value>::type {
cout << "Integral: " << value << endl;
}
template <typename T>
auto printIfIntegral(T value) -> typename enable_if<!is_integral<T>::value>::type {
cout << "Non-integral" << endl;
}
int main() {
printIfIntegral(42); // Integral
printIfIntegral(3.14); // Non-integral
}
应用场景:自动根据类型选择算法路径(如 SLAM 中整数索引 vs 浮点坐标)。
3. 可变参数模板(Variadic Templates)
处理任意数量的参数,非常适合构建日志系统、消息封装等。
#include <iostream>
using namespace std;
void log() { cout << endl; }
template<typename First, typename... Rest>
void log(First first, Rest... rest) {
cout << first << " ";
log(rest...);
}
int main() {
log("Frame", 42, "Processed", 3.14);
}
应用场景:SLAM 模块中多参数调试日志。
4. constexpr
模板(编译期计算)
在编译期生成结果,避免运行时开销。
#include <iostream>
using namespace std;
template <int N>
constexpr int factorial() {
if constexpr (N <= 1) return 1;
else return N * factorial<N-1>();
}
int main() {
constexpr int val = factorial<5>(); // 编译期计算
cout << val << endl;
}
应用场景:预计算查找表、矩阵维度等。
5. 模板与完美转发(Perfect Forwarding)
在泛型工厂、接口封装中保持参数类型和引用特性。
#include <iostream>
#include <utility>
using namespace std;
template <typename T, typename... Args>
T create(Args&&... args) {
return T(forward<Args>(args)...);
}
struct Pose {
Pose(double x, double y) { cout << "Pose(" << x << "," << y << ")\n"; }
};
int main() {
auto p = create<Pose>(1.0, 2.0);
}
应用场景:SLAM 中的统一对象工厂。
二、隐式转换高级应用
6. 转换运算符重载 + 模板化
支持多种目标类型的自动转换。
#include <iostream>
using namespace std;
struct Vector3 {
double x, y, z;
template<typename T>
operator T() const { return static_cast<T>(x + y + z); }
};
int main() {
Vector3 v{1, 2, 3};
double sum = v; // 转 double
int isum = v; // 转 int
cout << sum << ", " << isum << endl;
}
应用场景:允许向不同类型接口传递同一数据结构。
7. 结合 operator bool()
实现安全布尔判断
#include <iostream>
using namespace std;
class Sensor {
bool ok;
public:
Sensor(bool status) : ok(status) {}
explicit operator bool() const { return ok; } // 避免与 int 混用
};
int main() {
Sensor s(true);
if (s) cout << "Sensor OK\n";
}
应用场景:资源检查、设备状态判断。
三、explicit
高级应用
8. explicit
在模板构造函数中防止意外匹配
#include <iostream>
using namespace std;
template<typename T>
class Data {
T val;
public:
explicit Data(T v) : val(v) {}
};
int main() {
// Data<int> d = 42; // 编译错误
Data<int> d(42); // 必须显式
}
应用场景:防止模板构造函数与隐式类型转换冲突。
9. explicit
+ 转换运算符避免意外的算术运算
#include <iostream>
using namespace std;
struct Meters {
double value;
explicit operator double() const { return value; }
};
int main() {
Meters m{5.0};
double len = static_cast<double>(m); // 必须显式
cout << len << " m\n";
}
应用场景:物理单位系统,避免米和秒自动混算。
10. explicit
+ 多参数构造函数(C++20 支持)
C++20 起可以用 explicit(true/false)
控制构造函数隐式性。
#include <iostream>
using namespace std;
struct Point {
double x, y;
explicit(true) Point(double x, double y) : x(x), y(y) {}
};
int main() {
// Point p = {1.0, 2.0}; // 禁止隐式
Point p(1.0, 2.0); // 显式
}
应用场景:数据结构构造的严格控制。
高级建议
- 模板:在性能敏感的系统(如 SLAM)中,可结合
constexpr
和 SFINAE,避免运行时分支,提高编译期优化机会。 - 隐式转换:除非是数学类(向量、矩阵),否则建议限制隐式转换,防止接口误用。
- explicit:是 API 设计的“安全阀”,尤其在模板类和多参数构造中,防止隐式调用带来不可预测的行为。