C++模板之std::enable_if,函数模板的多态

中文标准库:enable_if

一、模板原型

template< bool B, class T = void >
struct enable_if;

当B为true时,则std::enable_if拥有等同于T的公开成员typedef type(即enable_if<B,T>::type);否则,无该成员typedef(VS会报错)

二、示例

void fun(){}

int testFunc()
{
    std::enable_if<std::is_function<decltype(fun)>::value, int>::type tt;  //这句相当于int tt;
    std::enable_if<std::is_function<int>::value, int>::type tt;  //报错,提示enable_if<false,int>没有成员type
}

三、用途

转载:std::enable_if的几种用法

1. 类型偏特化

在使用模板编程时,经常会用到根据模板参数的某些特性进行不同类型的选择,或者在编译时校验模板参数的某些特性。例如:

template <typename T, typename Enable=void>
struct check;
 
template <typename T>
struct check<T, typename std::enable_if<T::value>::type> {
  static constexpr bool value = T::value;
};

上述的 check 只希望选择 value==true 的 T,否则就报编译时错误。如果想给用户更友好的提示,可以提供结构体的原型定义,并在其中进行static_assert静态检查,给出更明确的字符串说明。

2. 控制函数返回类型

对于模板函数,有时希望根据不同的模板参数返回不同类型的值,进而给函数模板也赋予类型模板特化的性质。典型的例子可以参看tuple的获取第k个元素的get函数:

template <std::size_t k, class T, class... Ts>
typename std::enable_if<k==0, typename element_type_holder<0, T, Ts...>::type&>::type
get(tuple<T, Ts...> &t) 
{
  return t.tail; 
}
template <std::size_t k, class T, class... Ts>
typename std::enable_if<k!=0, typename element_type_holder<k, T, Ts...>::type&>::type
get(tuple<T, Ts...> &t) 
{
  tuple<Ts...> &base = t;
  return get<k-1>(base); 
}

由于函数模板不能偏特化,通过 enable_if 便可以根据 k 值的不同情况选择调用哪个 get,进而实现函数模板的多态

3. 校验函数模板参数类型

有时定义的模板函数,只希望特定的类型可以调用,参考cppreference官网示例,很好的说明了如何限制只有整型可以调用的函数定义:

template <typename T>
typename std::enable_if<std::is_const<T>::value&& std::is_integral<T>::value,const int>::type
get(T t)
{   //只有当T的类型为const int时,才可以调用get函数
	return t;
}

template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
is_odd(T t)
{   //偶数返回false
    return bool(t % 2);
}

template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even(T t)
{   //偶数返回true
    return !is_odd(t);
}

int main()
{
    std::cout<<get<const int>(2); 
    //std::cout << get<const float>(2.0);  //报错
    std::cout << is_odd<int>(2);  //false
    std::cout << is_even<int>(2); //true
}

一个通过返回值,一个通过默认模板参数,都可以实现校验模板参数是整型的功能。

posted @ 2021-09-10 15:40  滴哒哒哒  阅读(1084)  评论(0编辑  收藏  举报