2015-03-13 109 views
5

我無法理解第二個場景here。它說:enable_if添加一個具有默認參數的函數參數?

•方案2:添加具有默認參數的函數參數:

template <your_stuff> your_return_type_if_present 
yourfunction(args, enable_if_t<your condition, FOO> = BAR) { 
    // ... 
} 

方案2離開參數命名。您可以說::type Dummy = BAR,但名稱虛擬是無關緊要的,並且給它起一個名字很可能會觸發未引用的參數警告。您必須選擇FOO函數參數類型和BAR默認參數。你可以說int0,但然後你的代碼的用戶可能會意外地傳遞給函數一個額外的整數,將被忽略。相反,我們建議您使用void **,要麼0nullptr因爲幾乎沒有什麼可轉換爲void **

template <your_stuff> your_return_type_if_present 
yourfunction(args, typename enable_if<your_condition, void **>::type=nullptr) { 
// ... 
} 

如果方案2離開參數然後可以把它用什麼無名? 有沒有辦法讓這樣的代碼與enable_if一起工作?

enum otype {oadd,omull}; 
template<otype o> 
int add(int num1, std::enable_if<o == oadd, int>::type int= num2) 
{ 
    if (o == omull) return num1 * num1; 
    if (o == oadd) return num1 + num2; 
} 
+0

使用重載例如當(AB),它可以是有用的。 – BartoszKP 2015-03-13 19:08:56

+0

無法到達'omull'部分。 – Jarod42 2015-03-13 19:22:04

+0

enable_if啓用該功能,而不是參數。 – 2015-03-13 19:39:23

回答

3

enable_if實例(如果它幫助):

對於使用非void返回類型的功能:

對於單條件:

template <template T, typename std::enable_if<!std::is_same<T,std::string>::value>::type* = nullptr > 
T func(T x){} 

對於多個條件:

template <template T, typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type* = nullptr > 
T func(T x){} 


對於void返回類型的功能:

對於單條件:

template <template T> 
typename std::enable_if<!std::is_same<T,std::string>::value>::type 
func(T x){} 

對於多個條件:

template <template T> 
typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type 
func(T x){} 

不要忘了包括#include <type_traits>

6

微軟的文檔there 存在都不清晰。改爲使用this

提供了一個函數模板與形式的一位不願透露姓名的默認參數:

typename enable_if<your_condition, void **>::type = nullptr 

(如MS隸建議),就能發揮作用 - 只有在外殼和 - 你希望 寫的多個重載具有不同行爲的函數模板 ,它們由一個或多個模板參數控制。然後,通過 與表達上的模板參數(一個或多個)適當 要求的條件更換your_condition,你可以爭取SFINAE 原則來選擇要實例化 給出模板參數的具體超載。

SFINAE參數 - 我們稱之爲 - 爲 未被實例化的函數使用;它僅存在於函數模板 重載解析中激發SFINAE。因此它可能是無名的,因此它必須默認爲: 當您調用函數模板時,它不能強制您提供額外的無用參數。

例如:

#include <type_traits> 
#include <iostream> 

template <typename T> 
T foo(T && t, 
    typename std::enable_if<std::is_same<T,int>::value, void **>::type = nullptr) 
{ 
    std::cout << "Doubling " << t << " gives " << (t + t) << std::endl; 
    return t + t; 
} 

template <typename T> 
T foo(T && t, 
    typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr) 
{ 
    std::cout << "Squaring " << t << " gives " << (t * t) << std::endl; 
    return t * t; 
} 

using namespace std; 

int main() 
{ 
    cout << foo(2) << endl; 
    cout << foo(3.3) << endl; 
    return 0; 
} 

輸出是:

Doubling 2 gives 4 
4 
Squaring 3.3 gives 10.89 
10.89 

在功能模板foo這兩種過載,第一個加倍它是 類型T參數,第二個正方形它的參數,並且使用SFINAE 參數來確定如果T是,則將實例化加倍過載,否則將選擇平方過載。

Tint,條件:

!std::is_same<T,int>::value 

控制所述平方過載的SFINAE參數爲假。因此 類型說明符:

typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr 

無法編譯。這是模板解析中的替代失敗。將 int替換爲T中的平方過載爲不可行。所以平方過載從運行中消除了 ,並且只剩下加倍過載來實例化函數調用 。

T是(說)double,而不是int,則剛好相反發生 ,只有平方超載生存模板的分辨率。撥打電話foo(2) ,你會倍增。撥打電話foo(3.3)即可。

MS的標本SFINAE參數在這裏是不必要的冗長。

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

按C++ 11標準和更高版本,默認Tvoid。所以類似的:

typename std::enable_if<some_condition, void **>::type = nullptr 

能以及簡寫爲:

typename std::enable_if<some_condition>::type * = nullptr 

,並作爲C++ 14的標準有:

template< bool B, class T = void > 
using enable_if_t = typename enable_if<B,T>::type 

因此同樣SFINAE參數進一步縮短爲:

std::enable_if_t<some_condition> * = nullptr 

應用一個SFINAE函數模板參數,你已經在你的 後做了個手勢的情況下,你會寫類似的:

enum ops { 
    add, 
    multiply 
}; 

template<ops Op> 
int op(int const & lhs, int const & rhs, 
     std::enable_if_t<Op == add> * = nullptr) 
{ 
    return lhs + rhs; 
} 

template<ops Op> 
int op(int const & lhs, int const & rhs, 
     std::enable_if_t<Op == multiply> * = nullptr) 
{ 
    return lhs * rhs; 
} 

... 

auto i = op<add>(2,3); 
auto j = op<multiply>(2,3); 

... 
// C++14 
+0

謝謝!我終於找到了關於在SFINAE中使用'enable_if'的明確解釋。你的回答讓我學到很多東西!一直到'std :: enable_if_t * = nullptr'的縮寫真的很有幫助!我想問爲什麼把'void **'縮寫爲'std :: enable_if :: type *',後者我認爲其實是'void *'?欣賞它先進。 – astroboylrx 2016-04-26 06:49:42