MST

星途 面试题库

面试题:C++ SFINAE 在元编程中的应用

在 C++ 元编程中,SFINAE 起着关键作用。请描述如何利用 SFINAE 结合模板元编程来实现一个编译期的类型筛选器。比如,实现一个模板类 `TypeFilter`,它接受一个类型列表和一个条件,在编译期筛选出符合条件的类型,并通过特化模板类来展示筛选结果。要求阐述设计思路并给出核心代码实现。
24.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 定义类型列表:使用模板参数包来表示类型列表。
  2. 定义条件判断:通过模板特化来定义类型需要满足的条件。
  3. 实现筛选逻辑:利用 SFINAE(Substitution Failure Is Not An Error),在模板实例化过程中,如果类型不满足条件,替换失败但不报错,从而实现筛选。
  4. 展示筛选结果:通过特化模板类,将满足条件的类型保留,不满足的类型剔除。

核心代码实现

#include <iostream>
#include <type_traits>

// 定义一个类型特征用于条件判断,这里以是否为整数类型为例
template <typename T>
struct IsIntegerType : std::is_integral<T> {};

// 类型列表节点
template <typename T, typename... Ts>
struct TypeList {
    using Head = T;
    using Tail = TypeList<Ts...>;
};

// 空类型列表
template <>
struct TypeList<> {};

// 筛选器模板类
template <typename List, template <typename> class Condition>
struct TypeFilter;

// 特化:空类型列表
template <template <typename> class Condition>
struct TypeFilter<TypeList<>, Condition> {
    using Result = TypeList<>;
};

// 特化:非空类型列表,当前类型满足条件
template <typename T, typename... Ts, template <typename> class Condition>
std::enable_if_t<Condition<T>::value, void>
append_type(TypeList<T, Ts...>&, TypeList<T>& result) {
    result = {T{}};
    append_type(TypeList<Ts...>{}, result.Tail);
}

// 特化:非空类型列表,当前类型不满足条件
template <typename T, typename... Ts, template <typename> class Condition>
std::enable_if_t<!Condition<T>::value, void>
append_type(TypeList<T, Ts...>&, TypeList<> &result) {
    append_type(TypeList<Ts...>{}, result);
}

// 特化:非空类型列表
template <typename T, typename... Ts, template <typename> class Condition>
struct TypeFilter<TypeList<T, Ts...>, Condition> {
    using Result = typename decltype([] {
        TypeList<> result;
        append_type(TypeList<T, Ts...>{}, result);
        return result;
    })::type;
};

// 打印类型列表
template <typename List>
struct PrintTypeList;

template <>
struct PrintTypeList<TypeList<>> {
    static void print() {}
};

template <typename T, typename... Ts>
struct PrintTypeList<TypeList<T, Ts...>> {
    static void print() {
        std::cout << typeid(T).name() << std::endl;
        PrintTypeList<TypeList<Ts...>>::print();
    }
};

int main() {
    using MyList = TypeList<int, float, double, char>;
    using FilteredList = TypeFilter<MyList, IsIntegerType>::Result;
    PrintTypeList<FilteredList>::print();
    return 0;
}

上述代码实现了一个简单的类型筛选器 TypeFilter,它从类型列表 MyList 中筛选出整数类型。通过 IsIntegerType 这个条件判断模板类,结合 SFINAE 技术,在编译期完成筛选操作,并通过 PrintTypeList 打印出筛选后的类型列表。