$ g++ type_traits.cpp type_traits.cpp: In function ‘int main()’: type_traits.cpp:6:26: error: no matching function for call to ‘sqrt<double>(double)’ 6 | std::sqrt<double>(1.0); // compile error | ^ In file included from type_traits.cpp:1: /usr/include/c++/9/cmath:475:5: note: candidate: ‘template<class _Tp> constexpr typename __gnu_cxx::__enable_if<std::__is_integer<_Tp>::__value, double>::__type std::sqrt(_Tp)’ 475 | sqrt(_Tp __x) | ^~~~ /usr/include/c++/9/cmath:475:5: note: template argument deduction/substitution failed: /usr/include/c++/9/cmath: In substitution of ‘template<class _Tp> constexpr typename __gnu_cxx::__enable_if<std::__is_integer<_Tp>::__value, double>::__type std::sqrt(_Tp) [with _Tp = double]’: type_traits.cpp:6:26: required from here /usr/include/c++/9/cmath:475:5: error: no type named ‘__type’ in ‘struct __gnu_cxx::__enable_if<false, double>’
$ clang++ type_traits.cpp type_traits.cpp:6:5: error: no matching function for call to 'sqrt' std::sqrt<double>(1.0); // compile error ^~~~~~~~~~~~~~~~~ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/cmath:475:5: note: candidate template ignored: substitution failure [with _Tp = double]: no type named '__type' in '__gnu_cxx::__enable_if<false, double>' sqrt(_Tp __x) ^ 1 error generated.
这样的定义使用了 C++ 非类型模板参数与模板偏特化的特性。enable_if 的第一个参数是个 bool 类型的非类型模板参数 B,可以被赋值。然后 enable_if 又被偏特化出了一个 B 为 true 的结构,此结构中定义将模板参数 T 重命名为了 type。通过这样的操作,只有 std::enable_if<true, T> 的时候能过够通过作用域符导出 type,并且 type 就是 T 这个类型,如果 B == false,则不存在可以导出 type 的类型,导致类型不存在的编译错误。
简单来说,就是 typename std::enable_if<B, T>::type 的作用就是当 B 为 true 时,这个语句就相当于 T,否则就是不存在的类型。