面试题答案
一键面试- SFINAE(Substitution Failure Is Not An Error)原理:
- 当模板实例化过程中,对函数模板进行重载决议时,如果一个模板的替换(将模板参数替换到函数声明中)导致无效类型或表达式,这不会被视为编译错误,而是该模板被简单地从候选函数集中移除。
- 使用 SFINAE 实现条件编译:
- 类型特征检测:
- 例如,使用
std::is_integral
检测类型是否为整数类型。std::is_integral<T>::value
在T
是整数类型时为true
,否则为false
。 - 对于自定义类型,可以通过模板特化来自定义类型特征。比如定义一个判断类型是否有特定成员函数的特征:
- 例如,使用
- 类型特征检测:
// 主模板,默认情况下 HasMemberFunction 为 false
template <typename T, typename = void>
struct HasMemberFunction : std::false_type {};
// 特化模板,当 T 有 memberFunction 成员函数时为 true
template <typename T>
struct HasMemberFunction<T, std::void_t<decltype(std::declval<T>().memberFunction())>> : std::true_type {};
- 模板特化:
- 假设我们有一个模板函数
print
,在某些类型下会编译错误,比如非整数类型。
- 假设我们有一个模板函数
// 主模板函数
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
print(T value) {
std::cout << value << std::endl;
}
// 可以为其他类型提供另外的特化版本(这里简单忽略非整数类型)
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, void>::type
print(T value) {
// 不做任何处理或者给出提示信息
}
- 在模板类中使用:
- 假设有一个模板类
MyClass
,它依赖于某些类型的特定属性。
- 假设有一个模板类
template <typename T>
class MyClass {
// 只有当 T 是整数类型时才会有这个成员
typename std::enable_if<std::is_integral<T>::value, T>::type data;
public:
MyClass() {
if constexpr (std::is_integral<T>::value) {
data = 0;
}
}
};
- 在模板元编程库中的应用:
- 对于模板类和模板函数相互依赖的情况,当检测到错误类型组合时,利用 SFINAE 移除相关模板实例化。
- 例如,如果一个模板函数
func
依赖于另一个模板类Dependency
的成员,并且在某些类型下Dependency
没有该成员:
template <typename T>
class Dependency {
// 假设某些类型下没有 member 成员
};
// 为 Dependency 有 member 成员的类型特化
template <typename T>
class Dependency<T, std::enable_if<HasMemberFunction<T>::value>> {
public:
void member() {}
};
template <typename T>
typename std::enable_if<HasMemberFunction<T>::value, void>::type
func(T obj) {
Dependency<T> dep;
dep.member();
}
通过上述类型特征检测和模板特化技术结合 SFINAE 原理,可以在编译期避免错误类型组合导致的编译错误,使得相关代码在不满足条件时不参与编译。