目录:
trick:Hands-On Design Patterns With C++(零)前言zhuanlan.zhihu.comSFINAE与重载解析管理(上):
trick:Design Patterns With C++(七)SFINAE与重载解析管理(上)zhuanlan.zhihu.com本章代码:
https://github.com/PacktPublishing/Hands-On-Design-Patterns-with-CPP/tree/master/Chapter07github.comSFINAE与重载解析管理(中)
SFINAE: Substitution Failure Is Not An Error 匹配失败不是错误
我们本章将讨论以下几个话题:
- 什么是函数重载与重载解析?(见上篇)
- 什么是类型演绎和类型匹配?(见上篇)
- SFINAE是什么?为什么它对C++来说十分重要?(本文)
- 如何使用SFINAE编写复杂的程序?(本文及下一篇文章)
SFINAE是什么?SFINAE 替换失败不是错误
此规则的含义是:类型推断引起的替换失败不会引起整个程序发生错误。此规则对于C++模板方法十分重要,没有SFINAE,就无法编写出很多有效的程序。
考虑如下模板重载,一个是普通指针,一个是成员指针:
template <typename T>
void f(T* i) {
// 普通指针
std::cout << "f(T*)" << std::endl;
}
template <typename T>
void f(int T::* p) {
// 成员指针
std::cout << "f(T::*)" << std::endl;
}
struct A {
int i;
int f() {
return 0; }
};
int main() {
A a;
f(&a.i); // f(T*)
f(&A::i); // f(T::*)
}
考虑如下代码:
int i;
f(&i); // f(T*)
上述代码与f(T*)重载方法完全匹配,而与f(T::*)无效,编译器遇到f(T::*)方法发现会导致语法错误,就会静默忽略此重载方法。
SFINAE对于无效类型也没有限制,比如不存在的类成员引用。替换失败有很多方式:
template <size_t N>
void f(char(*)[N % 2] = NULL) {
std::cout << "N=" << N << " is odd" << std::endl;
}
template <size_t N>
void f(char(*)[1 - N % 2] = NULL) {
std::cout << "N=" << N << " is even" << std::endl;
}
int main() {
f<5>(); // N=5 is odd
f<8>(); // N=8 is even
}
上例中,f(char(*)[N % 2] = NULL)的版本适用于奇数(5 % 2 == 1),f(char(*)[1 - N % 2] = NULL)适用于偶数版本(1 - 8 % 2 = 1)。在调用f重载方法时,两个重载中其中一个会被静默忽略,否则会引起歧义失败。
template<typename T, size_t N = T::N>
void f(T t, char(*)[N % 2] = NULL) {
std::cout << "N=" << N << " is odd" << std::endl;
}
template<typename T, size_t N = T::N>
void f(T t, char(*)[1 - N % 2] = NULL) {
std::cout << "N=" << N << " is even" << std::endl;
}
struct A {
enum {
N =