MST

星途 面试题库

面试题:C++ 复杂场景下 SFINAE 在模板扩展的深度应用

在一个大型项目中,有一系列模板类 `BaseTemplate<T>` 及其派生模板类 `DerivedTemplate1<T>`、`DerivedTemplate2<T>` 等。要求实现一个通用的模板函数 `dispatch`,它能够根据传入对象的实际类型(无论是 `BaseTemplate` 还是其派生类),利用 SFINAE 机制,动态选择并调用不同的处理函数。这些处理函数需要根据模板参数 `T` 的不同特性(比如是否为指针类型、是否为标准容器类型等)进一步做差异化处理。请设计并完整实现 `dispatch` 函数以及相关的辅助类型特征和处理函数,并详细阐述设计思路和实现要点。
33.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 类型特征检测:利用模板元编程技术,定义一系列类型特征(type traits)来检测模板参数 T 的特性,如是否为指针类型、是否为标准容器类型等。
  2. SFINAE 机制:通过 SFINAE(Substitution Failure Is Not An Error)机制,在编译期根据类型特征来选择合适的处理函数。当模板参数替换失败时,不会导致编译错误,而是该函数模板被排除在候选函数之外。
  3. 动态调度dispatch 函数作为入口,接受 BaseTemplate<T> 类型的对象引用,根据对象的实际类型和 T 的特性,利用 SFINAE 选择合适的处理函数。

实现要点

  1. 类型特征定义:使用 std::is_pointerstd::is_same 等标准库类型特征,以及自定义的针对标准容器的类型特征。
  2. 处理函数重载:为不同类型特征组合定义不同的处理函数,利用 SFINAE 让编译器选择合适的函数。
  3. 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 函数的实现共同构成了整个动态调度机制。