C++ 函数模版实现SFINAE

Chris Scoot
4 min readOct 12, 2024

由于函数模版无法偏特化,只能重载,故而无法像类模版一样可以很方便的通过偏特化机制,实现条件选择。不过还是可以通过一些技巧来实现分支选择,例如下面两个函数模版,一个用于非整形变量,一个用于整形变量。

///T不是整数,调用此模版。通过返回值类型使得当T是整形时,该模版无效,故而两个函数模版互斥。
template <typename T>
std::enable_if<!std::is_integral_v<T>>::type fun11(T&) {
std::cout << "other" << std::endl;
}

///T是整数 调用此模版——通过默认参数类型使得,当T不是整形时,该模版无效
template <typename T,typename = std::enable_if<std::is_integral_v<T>>::type >
void fun11(T&) {
std::cout << "intergal" << std::endl;
}

int main() {
int aa;
double ffff1;

fun11(aa);///调用intergal
fun11(ffff1);///调用 other
}

使用这种技巧有几个需要注意的地方:

  • 防止函数模版重定义,两个模版名字一样,模版参数个数一样,函数参数个数类型一样就被认为是一个模版(函数返回值类型不算)
  • 各个函数模版必须互斥,否则编译器无法选择

你可能会说,上面只有2个分支,如果是多个分支呢?下面来实现3个分支:

template <typename T>///仅当T为C数组类型是有效
std::enable_if<std::is_array_v<T>>::type fun11(T&) {
std::cout << "array" << std::endl;
}

///仅当T为整形时有效
template <typename T,typename = std::enable_if<std::is_integral_v<T>>::type >
void fun11(T&) {
std::cout << "intergal" << std::endl;
}
///仅当T是结构体类型是有效
///由于模版参数个数,和函数参数个数类型和上面一样,会被认为是相同模版,所以多加一个默认模版参数
template <typename T,typename = std::enable_if<std::is_class_v<T>>::type ,bool = false>
void fun11(T&) {
std::cout << "class" << std::endl;
}

struct AA {};

int main() {
char array[4];
int aa;
double ffff1;
AA cls;

fun11(cls); ///调用class
fun11(array);///调用array
fun11(aa);///调用intergal

fun11(ffff1);///编译错误,No matching function for call to func11
}

3个模版必须互斥,否则编译器无法选择;由于上面只处理了3种情况,如果传递的类型不属于这三种情况中任何一个则编译报错。

可以看到,虽然函数模版也能实现多分支,但是较为繁琐。C++17以后引入constexpr if ,则更为方便

C++17 的 constexpr if

这种情况,代码就简单了。编译器会自动忽略不满足条件的分支,即便该分支语法有问题。不满足条件的分支不参与编译,有点类似于宏定义的if/else

template<typename T>
void f(T p) {
if constexpr (condition<T>::value) { // do something here...

}else {// not a T for which f() makes sense:
static_assert(condition<T>::value, "can’t call f() for such a T"); }
}
}

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Chris Scoot
Chris Scoot

Written by Chris Scoot

擅长C语言、C++、iOS开发(Objective-C\Swift)、Flutter开发(Dart语言)、GO语言、Python等,拥抱新技术,热爱AI领域,对OpenCV、Pytorch\Tensorflow充满热情。

No responses yet