2012-11-15 63 views
11

我想根據類模板參數來確定調用哪個版本的成員函數。我曾經嘗試這樣做:使用不同的enable_if條件選擇成員函數

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct Point 
{ 
    void MyFunction(typename std::enable_if<std::is_same<T, int>::value, T >::type* = 0) 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    void MyFunction(typename std::enable_if<!std::is_same<T, int>::value, float >::type* = 0) 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

int main() 
{ 
    Point<int> intPoint; 
    intPoint.MyFunction(); 

    Point<float> floatPoint; 
    floatPoint.MyFunction(); 
} 

而且我認爲他是說:「使用第一MyFunction的,如果T是int和使用第二的MyFunction如果T不是整數,但我得到的編譯器錯誤說」錯誤:無類型命名'type'in'struct std :: enable_if'「。任何人都可以指出我在這裏做錯了什麼嗎?

+0

相關Q&A:「發生了什麼事我SFINAE」(終極版)(HTTP:/ /stackoverflow.com/questions/11531989/what-happened-to-my-sfinae-redux-conditional-template-class-members) – HostileFork

回答

11

enable_if工作原因是substitution of a template argument resulted in an error,所以替代從重載解析集中刪除,只有其他可行的重載被編譯器考慮。

在你的例子中,沒有替換髮生ng,因爲當時已經知道模板參數T。實現你嘗試的最簡單的方法是創建一個虛擬模板參數,默認爲T並使用它來執行SFINAE。

template<typename T> 
struct Point 
{ 
    template<typename U = T> 
    typename std::enable_if<std::is_same<U, int>::value>::type 
    MyFunction() 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename U = T> 
    typename std::enable_if<std::is_same<U, float>::value>::type 
    MyFunction() 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

編輯:

由於HostileFork在評論中提到,最初的例子離開的用戶顯式指定模板參數的成員函數,卻得到了不正確的結果的可能性。以下應防止成員函數的顯式特化編譯。

template<typename T> 
struct Point 
{ 
    template<typename... Dummy, typename U = T> 
    typename std::enable_if<std::is_same<U, int>::value>::type 
    MyFunction() 
    { 
    static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!"); 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename... Dummy, typename U = T> 
    typename std::enable_if<std::is_same<U, float>::value>::type 
    MyFunction() 
    { 
    static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!"); 
    std::cout << "T is not int." << std::endl; 
    } 
}; 
+0

在C++ 11中,SFINAE規則已被修改了一點點,因此SFINAE將會不在返回類型上觸發。總之,這個答案是錯誤的。 – Nawaz

+0

@Nawaz在gcc4.7.2上工作得很好,自LWS關閉後無法發佈演示鏈接。 [這是](https://ideone.com/J0j3IK)ideone演示。 – Praetorian

+0

這不是C++ 11-conformant代碼的證明。 – Nawaz

1

enable_if僅適用於推斷函數模板參數或專門的類模板參數。你在做什麼是行不通的,因爲顯然在固定T = int的情況下,第二個聲明是錯誤的。

這是怎麼可以做到:

template <typename T> 
void MyFreeFunction(Point<T> const & p, 
        typename std::enable_if<std::is_same<T, int>::value>::type * = NULL) 
{ 
    std::cout << "T is int" << std::endl; 
} 

// etc. 

int main() 
{ 
    Point<int> ip; 
    MyFreeFunction(ip); 
} 

另一種方法是專門Point各類T,或把上面的免費功能到嵌套成員模板包裝(這可能是更「適當的」解決方案)。

+0

我見過這個解決方案,但它似乎真的破壞了代碼的可讀性。 –

+0

@DavidDoria:原始代碼太過於人爲製作更適合的建議。 –

+0

@DavidDoria如果你的情況是你只是使用SFINAE來檢查某些類型是否是'is_same'(如果那些不匹配,那麼它們有一個默認值),那麼針對這些固定類型的模板特化'Point'就是你通緝。你會有更可讀的定義相同的實例化。 – HostileFork

2

一個簡單的解決方案是使用代表團工人私人功能:

template<typename T> 
struct Point 
{ 

    void MyFunction() 
    { 
    worker(static_cast<T*>(0)); //pass null argument of type T* 
    } 

private: 

    void worker(int*) 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename U> 
    void worker(U*) 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

Tint,第一worker函數將被調用,因爲static_cast<T*>(0)原來是int*類型。在所有其他情況下,將調用模板版本的工作人員。

+1

我其實很喜歡這個。我不認爲我會使用它,但OP的例子是如此人爲設計,這確實是一個很好的解決方案。 –

+1

static_cast (nullptr) –

0

基於執政官的建議(但不改變函數的返回類型),這似乎工作:

#include <iostream> 
#include <type_traits> 

template<typename T> 
struct Point 
{ 
    template<typename U = T> 
    void MyFunction(typename std::enable_if<std::is_same<U, int>::value, U >::type* = 0) 
    { 
    std::cout << "T is int." << std::endl; 
    } 

    template<typename U = T> 
    void MyFunction(typename std::enable_if<!std::is_same<U, int>::value, float >::type* = 0) 
    { 
    std::cout << "T is not int." << std::endl; 
    } 
}; 

int main() 
{ 
    Point<int> intPoint; 
    intPoint.MyFunction(); 

    Point<float> floatPoint; 
    floatPoint.MyFunction(); 
} 
相關問題