2014-01-08 97 views
0

我想通過它的模板參數的類型特徵來專門化模板類上的成員函數,但是我的前向聲明顯然是不正確的。有一個簡單的解決方法嗎?按類型專門化模板類成員函數

#include <type_traits> 

template <typename T> 
class TTest{ 
public: 
    T data; 

    // edited to comment this out, template<typename U> 
    bool operator !=(const TTest& other) const; 
}; 

template <typename T> 
typename std::enable_if<std::is_unsigned<T>::value, bool>::type 
TTest<T>::operator !=(const TTest<T>& other) const{ 
    return true; 
} 

template<typename T> 
bool TTest<T>::operator !=(const TTest<T>& other) const{ 
    return false; 
} 

int main(){ 
    TTest<size_t> t1; 
    TTest<int> t2; 
} 

鏘告訴我:

templateTest.cpp:13:11: error: out-of-line definition of 'TTest::operator!=' 
    differs from the declaration in the return type 
TTest<T>::operator !=(const TTest<T>& other) const{ 
     ^
templateTest.cpp:8:8: note: previous declaration is here 
    bool operator !=(const TTest& other) const; 
    ^
1 error generated. 
+0

此代碼沒有意義。成員模板對模板參數具有* no *依賴性,所以沒有什麼特別的。 –

+0

你是否意識到'const TTest&other'是指你rmember模板中的'const TTest &other'? –

+0

你不能部分地專門化一個函數模板。如果你想要一個無符號T和非無符號T的版本,那麼你需要重載+ SFINAE或部分專門化整個類模板。 – dyp

回答

4

看起來好像整個012bshebang是函數簽名的一部分(或者我真的不明白錯誤)。我可以得到代碼編譯和行爲,只要你想,如果我將其更改爲

template <typename T> 
class TTest{ 
public: 
    T data; 

    template<typename U> 
    typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 

    template<typename U> 
    typename std::enable_if<not std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 
}; 

template <typename T> 
template <typename U> 
typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>&) const{ 
    return true; 
} 

template <typename T> 
template <typename U> 
typename std::enable_if<not std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>&) const{ 
    return false; 
} 

Live demo。當然,如果將這些運算符定義爲內聯,這會減少很多重複性。

更好的方法可能是根據T的特性分派到運營商邏輯的不同私有實現。這會從您的代碼中刪除所有SFINAE詳細信息。

template <typename T> 
class TTest{ 
public: 
    T data; 

    bool operator!=(const TTest& other) const 
    { 
     return not_equal_to(other, typename std::is_unsigned<T>::type()); 
    } 

private: 
    bool not_equal_to(TTest const&, std::true_type) const 
    { 
     return true; 
    } 

    bool not_equal_to(TTest const&, std::false_type) const 
    { 
     return false; 
    } 
}; 

Live demo

+0

第一個答案似乎工作,但我有2個問題:如果我內聯這些定義,我得到含糊/無法推斷錯誤(取決於如果我使用。任何想法爲什麼?其次,我並不是真的想要比較不同類型的TTests,但這種方法似乎允許它。任何方式? –

+0

我沒有[得到任何錯誤](http:// coliru .stacked-歪。com/a/0db61b7bcec2cfd5)與內聯定義的gcc或clang。你無法擺脫'template ',因爲SFINAE需要模板參數推導才能工作。爲了確保不會比較不同類型,可以在定義中添加'static_assert(std :: is_same :: value,「」)''。無論如何,我建議你完全不使用'enable_if'並遵循第二種方法,除非有什麼阻止你這樣做。 – Praetorian

+0

哎呀,我錯過了一些內嵌的內容,也在我的機器上工作,謝謝。你爲什麼喜歡第二種方法?模板噪音較少? –

1

你宣佈你模板類的成員函數模板,您要專門爲成員函數。這不會飛。而且,返回類型不同,儘管最終評估的是同樣的事情。

我不知道你試圖嘗試什麼,因爲成員函數模板的U類型甚至沒有被推導出來(你的意思是參數類型爲TTest<U>?)。如果你想基於一個特點專門您的會員,我想你會要麼需要牛逼超載操作或使用不同的方法(例如,委託執行的專門類模板):

#include <iostream> 
#include <type_traits> 

template <typename T> 
class TTest{ 
public: 
    T data; 

    template<typename U> 
    typename std::enable_if<!std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 

    template<typename U> 
    typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 
}; 

template <typename T> 
template<typename U> 
typename std::enable_if<!std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>& other) const { 
    return true; 
} 

template <typename T> 
template<typename U> 
typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>& other) const { 
    return false; 
} 

int main(){ 
    TTest<unsigned int> t1; 
    TTest<int> t2; 
    std::cout << std::boolalpha 
      << "t1 != t1: " << (t1 != t1) << '\n' 
      << "t1 != t2: " << (t1 != t2) << '\n' 
      << "t2 != t1: " << (t2 != t1) << '\n' 
      << "t2 != t2: " << (t2 != t2) << '\n'; 
} 
+0

在您的類聲明中,他會完成模板。然後這是有道理的(並會工作)。在另一端的可讀性.... – jyavenard

1

tag分派是乾淨的方法來做到這一點:

template <typename T> 
class TTest{ 
    bool not_equal(const ITest& other, std::true_type /* is unsigned */) const; 
    bool not_equal(const ITest& other, std::false_type /* is unsigned */) const; 
public: 
    T data; 

    bool operator !=(const TTest& other) const { 
    return not_equal(other, std::is_unsigned<T>()); 
    } 
}; 

現在簡單地實現這兩個TTest<T>::not_equal重載。只有實際調用給定T的那個將被編譯通過基本解析。