Tag dispatching 是一种利用函数重载与空标签类型在编译期选择实现的 C++ 模板技巧,核心是将类型特征转为函数参数类型以触发重载解析;它弥补了早期标准中模板缺乏条件分支能力的不足,相比 enable_if 更清晰,比 if constexpr 更兼容旧代码。
Tag dispatching 是一种利用函数重载 + 类型标签(空类型)在编译期选择不同实现的 C++ 模板技巧,核心是把“类型特征”转化为“函数参数类型”,让重载解析替你做分支决策。
模板本身不支持基于类型特性的条件分支(比如“如果 T 是 integral,走 A;如果是浮点,走 B”),而 if constexpr(C++17)虽能解决,但在早期标准或需兼容旧代码时,tag dispatching 是稳定、清晰且零开销的替代方案。它把编译期判断“外推”到函数重载机制上——而重载解析本就是编译期完成的。
分三步:定义标签类型 → 写带标签参数的重载函数 → 在主模板中传入对应标签。
struct integral_tag {}; struct floating_point_tag {};
void impl(int x, integral_tag) { /* 处理整数 */ }
void impl(double x, floating_point_tag) { /* 处理浮点 */ }template
void foo(T x) {
impl(x, typename std::is_integral_v? integral_tag{} : floating_point_tag{}); // ❌ 错!不能 runtime 选
impl(x, typename std::is_integral::type{ }); // ✅ 正确:用 std::true_type / std::false_type
}
更常见的是直接用标准库的 std::true_type 和 std::false_type(它们本质就是空 struct,分别继承自 std::integral_constant 等),省去自定义。
三者都用于编译期分派,但风格和适用场景不同:
假设你想写一个通用的 sum_range,对随机访问迭代器用下标加速,对前向迭代器只用 ++:
std::iterator_traits::iterator_category 获取类别标签(如 std::random_access_iterator_tag)sum_impl 重载,参数分别是该标签类型typename std::iterator_traits::iterator_category{}
这样编译器在调用时就自动选最优路径,无运行时开销,也无需手动特化整个模板。