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
}

一個通過返回值,一個通過默認模板參數,都可以實現校驗模板參數是整型的功能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM