面试题答案
一键面试设计思路
- 类型特征检测:利用模板元编程技术,定义一系列类型特征(type traits)来检测模板参数
T
的特性,如是否为指针类型、是否为标准容器类型等。 - SFINAE 机制:通过 SFINAE(Substitution Failure Is Not An Error)机制,在编译期根据类型特征来选择合适的处理函数。当模板参数替换失败时,不会导致编译错误,而是该函数模板被排除在候选函数之外。
- 动态调度:
dispatch
函数作为入口,接受BaseTemplate<T>
类型的对象引用,根据对象的实际类型和T
的特性,利用 SFINAE 选择合适的处理函数。
实现要点
- 类型特征定义:使用
std::is_pointer
、std::is_same
等标准库类型特征,以及自定义的针对标准容器的类型特征。 - 处理函数重载:为不同类型特征组合定义不同的处理函数,利用 SFINAE 让编译器选择合适的函数。
dispatch
函数实现:接受BaseTemplate<T>
引用,通过static_cast
尝试转换为具体派生类类型,然后调用相应处理函数。
代码实现
#include <iostream>
#include <type_traits>
#include <vector>
#include <list>
// 基类模板
template <typename T>
class BaseTemplate {};
// 派生类模板1
template <typename T>
class DerivedTemplate1 : public BaseTemplate<T> {};
// 派生类模板2
template <typename T>
class DerivedTemplate2 : public BaseTemplate<T> {};
// 类型特征:检测是否为标准容器
template <typename T>
struct IsStandardContainer : std::false_type {};
template <typename T>
struct IsStandardContainer<std::vector<T>> : std::true_type {};
template <typename T>
struct IsStandardContainer<std::list<T>> : std::true_type {};
// 处理函数:针对指针类型
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type
handle_pointer(const T& ptr) {
std::cout << "Handling pointer: " << ptr << std::endl;
}
// 处理函数:针对标准容器类型
template <typename T>
typename std::enable_if<IsStandardContainer<T>::value, void>::type
handle_container(const T& cont) {
std::cout << "Handling container with size: " << cont.size() << std::endl;
}
// 处理函数:针对其他类型
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value &&!IsStandardContainer<T>::value, void>::type
handle_other(const T& obj) {
std::cout << "Handling other type" << std::endl;
}
// 通用调度函数
template <typename T>
void dispatch(const BaseTemplate<T>& base) {
if (const auto* derived1 = dynamic_cast<const DerivedTemplate1<T>*>(&base)) {
if (std::is_pointer<T>::value) {
handle_pointer(*static_cast<const T*>(derived1));
} else if (IsStandardContainer<T>::value) {
handle_container(*static_cast<const T*>(derived1));
} else {
handle_other(*static_cast<const T*>(derived1));
}
} else if (const auto* derived2 = dynamic_cast<const DerivedTemplate2<T>*>(&base)) {
if (std::is_pointer<T>::value) {
handle_pointer(*static_cast<const T*>(derived2));
} else if (IsStandardContainer<T>::value) {
handle_container(*static_cast<const T*>(derived2));
} else {
handle_other(*static_cast<const T*>(derived2));
}
}
}
测试代码
int main() {
DerivedTemplate1<int*> d1(new int(5));
dispatch(d1);
std::vector<int> vec = {1, 2, 3};
DerivedTemplate2<std::vector<int>> d2(vec);
dispatch(d2);
DerivedTemplate1<int> d3(10);
dispatch(d3);
return 0;
}
在上述代码中,dispatch
函数根据传入对象的实际类型和模板参数 T
的特性,通过 SFINAE 选择合适的处理函数进行处理。类型特征检测、处理函数重载以及 dispatch
函数的实现共同构成了整个动态调度机制。