std::enable_ifの使い方


一、試験手順1
#include 
#include 
using namespace std; 

template 
typename std::enable_if<:is_integral>::value,bool>::type
gt_zero (T i) { 
    cout << "is integral" << endl;
    return i>0;  
}
template 
typename std::enable_if::value,bool>::type
gt_zero (T i) { 
    cout << "is NOT integral" << endl;
    return i>0; 
}

int main() {
  short int i = 2;    
  float f = 3.1;
  std::cout << i << " greater than zero : " << gt_zero(i) << std::endl;
  std::cout << f << " greater than zero : " << gt_zero(f) << std::endl;
  return 0;
}

まずはgt_zeroはテンプレート関数でtypename std::enable_if<:is_integral>::value,bool>::typeは関数の戻り値タイプ、std::enable_if<>は一般的に2つの部分から構成され、最初のパラメータは判定式であり、判定式が真である場合std::enable_if<:is_integral>::value,bool>::typeのこのtypeデータメンバーが存在し、値はboolであり、2番目のパラメータがない場合、デフォルト値はvoidです.式が偽であると判定された場合、typeというデータメンバーは定義されておらず、値が何であるかは存在しない.
しかしコンパイラはtype値が存在しないからといってエラーを報告することはありません.汎用プログラミングには最適マッチングの原則が存在し、このテンプレートが成立しないので、他のテンプレートを推定します.だからgt_zeroは実際には同時にリロード関数です.
最初のパラメータstd::is_integral::valueが偽物の場合!std::is_integral::valueは本物に違いないので、2番目のテンプレート関数は要求に合致し、同じstd::enable_if<:is_integral>::value,bool>::typeの値はtrueです.
実行結果:
is integral 1 greater than zero : 1 is NOT integral 3.1 greater than zero : 1
上記の解析から2回の呼び出しが得られるgt_zero関数の最初の呼び出しは最初のバージョンで、2番目の呼び出しは2番目のバージョンです. 
二、試験手順2
#include 
#include 
using namespace std; 

template 
bool
gt_zero (T i, typename std::enable_if<:is_integral>::value, T>::type j=0) { 
    cout << "is integral" << endl;
    return i>0;  
}
template 
bool
gt_zero (T i, typename std::enable_if::value,T>::type j=0) { 
    cout << "is NOT integral" << endl;
    return i>0; 
}

int main() {
  short int i = 2;    
  float f = 3.1;
  std::cout << i << " greater than zero : " << gt_zero(i) << std::endl;
  std::cout << f << " greater than zero : " << gt_zero(f) << std::endl;
  return 0;
}

最初のプログラムの敷居があれば、2番目のテストプログラムはずっと簡単です.まずはgt_zero関数の戻り値タイプはboolタイプとして指定されていますgt_zero関数の2番目のパラメータtypename std::enable_if<:is_integral>::value,T>::type j=0はj変数が定義されていることを示しますが、typeはstd::is_integral::valueが成立した条件下で定義され、成立時typeの値はTであり、jという変数を定義する際の役割は、関数受信データ型の種類を制限することにすぎず、テンプレート関数を再ロードすることで、テンプレート関数が異なるデータ型に基づいて異なる関数数を実行できるようにする. 
実行結果:
is integral 2 greater than zero : 1 is NOT integral 3.1 greater than zero : 1
三、試験手順3
#include 
#include 
using namespace std; 

template ::value>::type* = nullptr>
bool
gt_zero (T i) { 
    cout << "is integral" << endl;
    return i>0;  
}
template ::value>::type* = nullptr>
bool
gt_zero (T i) { 
    cout << "is NOT integral" << endl;
    return i>0; 
}

int main() {
  short int i = 2;    
  float f = 3.1;
  std::cout << i << " greater than zero : " << gt_zero(i) << std::endl;
  std::cout << f << " greater than zero : " << gt_zero(f) << std::endl;
  return 0;
}

実行結果:
is integral 2 greater than zero : 1 is NOT integral 3.1 greater than zero : 1
四、std::is_integral
    :template< class T > struct is_integral;
  :   T        。  T   bool 、 char 、 char8_t 、 char16_t 、 char32_t 、wchar_t 、 short 、 int 、 long 、 
long long   ,              ,       、     cv      。      true       value 。
  , value   false 。