MST

星途 面试题库

面试题:C++函数模板与SFINAE技术应用

使用C++函数模板结合SFINAE(Substitution Failure Is Not An Error)技术,实现一个函数模板,该模板仅在类型T支持成员函数`size()`时才会被实例化,函数功能为返回T类型对象的`size()`结果。请写出详细代码,并解释SFINAE在此处的作用机制。
41.0万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
#include <iostream>
#include <type_traits>

// 辅助模板,用于检测类型T是否有size()成员函数
template <typename T, typename = void>
struct has_size_member : std::false_type {};

template <typename T>
struct has_size_member<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};

// 主函数模板,仅当T有size()成员函数时实例化
template <typename T, std::enable_if_t<has_size_member<T>::value, int> = 0>
auto get_size(T&& t) -> decltype(t.size()) {
    return t.size();
}

int main() {
    std::string s = "hello";
    std::cout << "Size of string: " << get_size(s) << std::endl;

    // 下面这行如果取消注释会编译错误,因为int没有size()成员函数
    // int num = 10;
    // std::cout << "Size of int: " << get_size(num) << std::endl;

    return 0;
}

SFINAE作用机制解释

  1. has_size_member模板
    • 首先定义了偏特化版本has_size_member<T, void>,默认情况下它继承自std::false_type,意味着在没有其他特化的情况下,假设类型T没有size()成员函数。
    • 然后定义了更具体的特化版本has_size_member<T, std::void_t<decltype(std::declval<T>().size())>>。这里使用了std::void_t来检查decltype(std::declval<T>().size())是否是一个有效的表达式。如果T类型的对象可以调用size()函数,那么decltype(std::declval<T>().size())是有效的,这个特化版本会被匹配,从而继承自std::true_type
  2. get_size函数模板
    • std::enable_if_t<has_size_member<T>::value, int> = 0std::enable_if的使用。它作为函数模板的一个额外模板参数,只有当has_size_member<T>::valuetrue时(即Tsize()成员函数),整个函数模板才是有效的。如果has_size_member<T>::valuefalse,那么这个函数模板会在重载决议阶段被忽略,而不会导致编译错误,这就是SFINAE技术“替换失败不是错误”的体现。这样就实现了仅当类型T支持size()成员函数时,get_size函数模板才会被实例化。