现在的位置: 首页 > 黄专家专栏 > 正文

模板的 SFINAE 原则

2014年10月30日 黄专家专栏 ⁄ 共 1704字 ⁄ 字号 评论关闭

模板函数的重载遵循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);             // 成功
}

抱歉!评论已关闭.