2015-07-19 142 views
14

我有一個工程,並使用std::enable_if下面的情況:爲什麼模板參數中的enable_if_t會抱怨重新定義?

template<typename T, 
     typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr> 
void f() { } 

template<typename T, 
     typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr> 
void f() { } 

現在,我在cppreference看到了新的語法,在我看來更清潔:typename = std::enable_if_t<std::is_same<int, T>::value>>

我想端口我的代碼:

template<typename T, 
     typename = std::enable_if_t<std::is_same<int, T>::value>> 
void g() { } 

template<typename T, 
     typename = std::enable_if_t<std::is_same<double, T>::value>> 
void g() { } 

但現在GCC(5.2)抱怨:

error: redefinition of 'template<class T, class> void g()' 
     void g() { } 

這是爲什麼呢?在這種情況下,如果可能的話,我能做些什麼來獲得新的,更簡潔的語法?

+5

你的第二個代碼使用默認的模板參數。它們不是函數簽名的一部分,因此您聲明瞭具有相同簽名=重定義的兩個函數模板。相應地使用'enable_if_t'實際上是'std :: enable_if_t :: value> * = nullptr'。 – dyp

+0

那麼,你沒有完全重寫你的原始代碼。你忘了'* = nullptr'。 –

+0

你可以爲其中一個聲明添加一個虛擬模板參數,比如'enable_if'後面的',typename = void' –

回答

23

我們刪除一些代碼。

template< 
    class T, 
    class U/* = std::enable_if_t<std::is_same<int, T>::value>*/ 
> 
void g() { } 

template< 
    class T, 
    class U/* = std::enable_if_t<std::is_same<double, T>::value>*/ 
> 
void g() { } 

如果編譯器拒絕了上述兩個模板,您會感到驚訝嗎?

它們都是「類型」template<class,class>void()的模板函數。事實上,第二種類型的參數具有不同的默認值值不重要。這就像是期待兩個不同的print(string, int)函數具有不同的默認值int值過載。;)

在我們的第一種情況:

template< 
    typename T, 
    typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr 
> 
void f() { } 

template< 
    typename T, 
    typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr 
> 
void f() { } 

在這裏我們不能刪除enable_if條款。更新到enable_if_t

template< 
    class T, 
    std::enable_if_t<std::is_same<int, T>::value>* = nullptr 
> 
void f() { } 

template< 
    class T, 
    std::enable_if_t<std::is_same<double, T>::value>* = nullptr 
> 
void f() { } 

我還更換了使用typenameclass。我懷疑你的困惑是因爲typename有兩個含義 - 一個作爲一種template參數的標記,另一個作爲依賴類型的消歧器。

這裏的第二個參數是一個指針,它的類型依賴於第一個參數。編譯器無法確定這兩個衝突是否在沒有首先替換類型T時發生衝突 - 並且您會注意到它們永遠不會發生衝突。

-6

你錯過了 「::型」 ..

template<typename T, 
      typename = std::enable_if_t<std::is_same<int, T>::value>::type> 
    void g() { } 

    template<typename T, 
      typename = std::enable_if_t<std::is_same<double, T>::value>::type> 
    void g() { } 
+2

'std :: enable_if_t'是'std :: enable_if'嵌套':: type'定義的別名模板。 –

2

對於函數的返回類型,你要找下列內容:

template<typename T> std::enable_if_t< conditional, instantiation result > foo(); 

例子:

#include <iostream> 

// when T is "int", replace with 'void foo()' 
template<typename T> 
std::enable_if_t<std::is_same<int, T>::value, void> foo() { 
    std::cout << "foo int\n"; 
} 

template<typename T> 
std::enable_if_t<std::is_same<float, T>::value, void> foo() { 
    std::cout << "foo float\n"; 
} 

int main() { 
    foo<int>(); 
    foo<float>(); 
} 

http://ideone.com/TB36gH

也看到

http://ideone.com/EfLkQy

6

enable_if_t<B>僅僅是typename enable_if<B>::type的別名。讓我們來代替,在g所以我們可以看到fg的真正區別:

template<typename T, 
     typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr> 
void f() { } 

template<typename T, 
     typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr> 
void f() { } 

template<typename T, 
     typename = typename std::enable_if<std::is_same<int, T>::value>::type> 
void g() { } 

template<typename T, 
     typename = typename std::enable_if<std::is_same<double, T>::value>::type> 
void g() { } 

f的情況下,我們都用模板參數<typename, X*>,其中類型X依賴兩個函數模板第一個模板的類型參數。在g的情況下,我們有兩個帶模板參數<typename, typename>的函數模板,它只是依賴的默認模板參數,所以C++認爲它們都聲明瞭同一個實體。

無論哪種風格可以用enable_if_t別名使用:

template<typename T, 
     std::enable_if_t<std::is_same<int, T>::value>* = nullptr> 
void f() { } 

template<typename T, 
     std::enable_if_t<std::is_same<double, T>::value>* = nullptr> 
void f() { } 

template<typename T, 
     typename = std::enable_if_t<std::is_same<int, T>::value>> 
void g() { } 

template<typename T, 
     typename = std::enable_if_t<std::is_same<double, T>::value>> 
void g() { } 
+0

如果我可以接受多個答案,我也會接受你的答案,因爲它同樣有效!謝謝 ! –

+0

沒問題,Yakk的解釋稍微好一點。 – Oktalist

相關問題