2016-08-12 34 views
2
enum class enabler{}; 

template<typename T> 
class X { 
    template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()> 
    void func(); 
    void func(int a); 
    void func(std::string b); 
}; 

我有這個類與這些3過載func。我需要第二個/第三個版本可用於類/非類類型,並且第一個版本僅適用於類類型。當我如上所述嘗試使用enable_if時,非類類型的類實例化會導致編譯錯誤。如何使用enable_if與過載

+3

SFINAE只適用於*推導*類型。 –

+1

能否詳細說明一下? – mkmostafa

+0

你實際上並不需要使用sfinae。你的情況下'static_assert'已經足夠了。在我的(晚)答案中看到最小的例子。 – skypjack

回答

1

對於SFINAE的工作,必須推導出模板參數。在你的情況下,當你嘗試實例化func時,T已知,所以如果enable_if條件是false而不是SFINAE,則會出現硬錯誤。

要修復錯誤,只需添加默認值爲T的模板參數,並在enable_if檢查中使用此新參數。現在扣除發生,並且SFINAE可以踢入非班級類型。

template<typename U = T, 
     typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()> 
void func(); 

而且你並不真的需要一個專門的enabler型兩種,這工作太

template<typename U = T, 
     typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr> 
void func(); 
+0

這種方法的缺點是你可以使用顯式模板參數運行'func()':即使'T'不是類 –

+0

@AndreiR,'func ()'也會導致類超載。是的,如果你想在腳下自己射擊,你總能找到一些方法來做到這一點。 – Praetorian

+0

@Praetorian您仍然可以使用一個像'template 類型的保護參數包,值> int> :: type * = nullptr> void FUNC();'。顯式模板參數將被剔除。 – skypjack

1

我真的不知道你有enabler去什麼在這裏,但你不能做你想要什麼,因爲自從T不受func推導出你的成員函數的聲明必須是有效的。爲了達到你想添加額外重載的目的,你可以使用一些適度設計的繼承。

struct XBaseImpl { 
    // whatever you want in both versions 
    void func(int a) { } 
    void func(std::string b) { } 
}; 

template <typename, bool> struct XBase; 

// is_class is true, contains the extra overload you want 
template <typename T> 
struct XBase<T, true> : XBaseImpl { 
    static_assert(std::is_class<T>{}, ""); // just to be safe 
    using XBaseImpl::func; 
    void func() { } // class-only 
}; 

// is_class is false 
template <typename T> 
struct XBase<T, false> : XBaseImpl { }; 

template<typename T> 
class X : public XBase<T, std::is_class<T>{}> { }; 
0

你是不是啓用或禁用的東西。
你只是想在一個特定情況下編譯時錯誤。
因此,你不需要依靠sfinae,static_assert就足夠了。

作爲一個最小的,工作示例:

#include<string> 

template<typename T> 
class X { 
public: 
    void func() { 
     static_assert(std::is_class<T>::value, "!"); 
     // do whatever you want here 
    } 

    void func(int a) {} 
    void func(std::string b) {} 
}; 

int main() { 
    X<int> x1; 
    X<std::string> x2; 

    x2.func(42); 
    x2.func(); 

    x1.func(42); 
    // compilation error 
    // x1.func(); 
} 

一旦SO用戶說我:這不是SFINAE,這是 - 替換故障始終是一個錯誤 - 在這種情況下,你應該使用static_assert而不是
他是對的,如上面的例子所示,static_assert比sfinae更容易編寫和理解,並且它的工作也是如此。