模板函数的重载遵循SFINAE原则(substitution-failure-is-not-an-error):当一个模板函数的返回值或参数类型无效的时候,该实例不会参与重载解析,也不会导致编译错误。
所以常用 is_same enable_if 等
is_same 表示两个类型是否相同 一般来说代码是这样实现的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// stl 实现 4.1.2
template<typename _Tp, _Tp __v>
struct integral_constant {
static const _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant<_Tp, __v> type;
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
// 定义了两个不同的 class,其中的 value是其值,有true和false两种
template<typename, typename>
struct is_same : public false_type { };
// 模板的偏特化
template<typename _Tp>
struct is_same<_Tp, _Tp> : public true_type { };
|
enable_if 表现的语义如下:
enable_if 如果 bool 是true,那么其 type 定义为 T 否则无定义
可能的实现如下:
1
2
3
4
5
6
|
template<typename, bool>
struct enable_if {};
template<typename _Tp>
struct enable_if<_Tp, true> {
typedef _Tp type;
};
|
有了这以上两个描述,我们演示一下模板的 SFINAE 原则:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
namespace test {
template<typename _Tp, _Tp __v>
struct integral_constant {
static const _Tp value = __v;
typedef _Tp value_type;
typedef integral_constant<_Tp, __v> type;
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
// 定义了两个不同的 class,其中的 value是其值,有true和false两种
//
template<typename, typename>
struct is_same : public false_type { };
//
// 模板的偏特化
template<typename _Tp>
struct is_same<_Tp, _Tp> : public true_type { };
template<bool, typename _Tp = void>
struct enable_if {};
template<typename _Tp>
struct enable_if<true, _Tp> {
typedef _Tp type;
};
}
class SfinaeTest {
public:
void Foo(double) {
std::cerr << "double" << std::endl;
}
template<class Tp>
typename test::enable_if<test::is_same<Tp, int>::value || test::is_same<Tp, std::string>::value>::type
Foo(Tp t) {
std::cerr << "Tp" << std::endl;
}
};
int main() {
SfinaeTest s;
s.Foo(1); // 成功,能够推导出 Tp = int
std::string str; // 成功,能够推导出 Tp = std::string
s.Foo(1.0); // 成功
}
|