現在的位置: 首頁 > 黃專家專欄 > 正文

模板的 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);             // 成功
}

抱歉!評論已關閉.

奔驰宝马破解版下载 股票下周一大盘分析 吉祥麻将手机版下载 平特一肖公式 南昌麻将免费下载 二分彩计划走势图 虎扑足球 闲来陕西麻将2 十个在家最挣钱的工作 专家股票推荐 追光娱乐老版 捕鱼上下分星力平台 国际象棋吃子规则 波克捕鱼不属于网赌吗 欢乐棋牌app网址 捕鱼王棋牌 闲来麻将贵州麻将