2011-08-23 184 views
2

我有一個索引函數,並試圖將其專用於標準容器類型,但會得到錯誤。我確信它不是簡單的就是不可能的,但我不記得哪一個。我更喜歡這些作爲功能對象,但我無法做到這一點。是否有可能專門的模板函數模板類模板類的專用模板函數

namespace std { //declarations of predefined indexable types 
    template <class T, class A> class vector; 
    //others are here too, but all have the same issue 
} 
//default indexer 
template <class T> 
double indexer(const T& b) { //this seems to work fine 
    return b.getIndex(); 
} 
// base types 
template<> double indexer<char>(const char& b) { return double(b); } 
//other primitives are here too, and work fine 
// standard library 
template<class T, class A> 
double indexer<std::vector<T,A>>(const std::vector<T,A>& b) 
{ return b.empty() ? 0 : indexer(*b.cbegin()); } //line with error 

錯誤消息:

error C2768: 'indexer' : illegal use of explicit template arguments 

我想爲這是專業化VS超載,因爲我有一個函數A,需要一個功能對象/指針模板參數,以及使用默認索引器調用第一個A的重載函數A

template<class T, class function> 
double A(T a, function F) { return F(a);} //complicated 
template<class T> 
double A(T a) {return A(a, indexer<T>);} //default wrapper 

這似乎很有可能這是一個重複的問題,但我似乎無法找到一個。

+3

函數模板的專門化是不需要的 - 使用重載代替。見[這裏](http://www.gotw.ca/publications/mill17.htm)爲什麼喜歡重載超過專門的功能模板。 – Simon

+0

你不能部分專門化功能模板。你可以把這個函數包裝到一個結構中,或者像@Simon所說的那樣創建單獨的重載。 –

+0

如果包裝器沒有模板化,是否有方法讓包裝器「A」選擇正確的索引器類型? –

回答

1

由於函數不能部分專用,我可以用函數對象替換索引函數。這似乎工作正常,並解決了我所有的問題。

namespace std { //declarations of predefined indexable types 
    template <class T, class A> class vector; 
} 
template <class T> 
struct indexer { 
    double operator()(const T& b) const 
    { return b.getIndex(); } 
}; 
template<> struct indexer<char> { 
    double operator()(const char& b) const 
    { return double(b); } 
}; 
template<class T, class A> struct indexer<std::vector<T,A>> { 
    double operator()(const std::vector<T,A>& b) const 
    { return b.empty() ? 0 : indexer(*b.cbegin()); } 
}; 

template<class T, class function> 
double A(T a, function F) { return F(a);} //complicated 
template<class T> 
double A(T a) {return A(a, indexer<T>());} //default wrapper 
2

您不能部分專門化模板功能,只能模板類。

超載使用,而不是:

namespace std { //declarations of predefined indexable types 
     template <class T, class A> class vector; 
} 
//default indexer 
template <class T> 
double indexer(const T& b) { return b.getIndex(); } 

double indexer(const char& b) { return double(b); } 

template<class T, class A> 
double indexer(const std::vector<T,A>& b) 
{ return b.empty() ? 0 : indexer(*b.cbegin()); } 
+0

你可以專注於模板功能。你不能**部分**專門化他們。如果你專門研究它們,你需要明確的類型。 –

0

這裏只對過載提供基於解決方案,使用C++ 11式可變參數模板:

template <typename T> 
T print(const T & t) 
{ 
    std::cout << t << std::endl; 
    return t; 
} 

template <template <typename...> class Container, typename ...Args> 
typename Container<Args...>::value_type print(const Container<Args...> & v) 
{ 
    typedef typename Container<Args...>::value_type T; 

    if (v.empty()) std::cout << "nil" << std::endl; 
    else std::cout << *v.begin() << std::endl; 

    return v.empty() ? T() : *v.begin(); 
} 

如果你想成爲幻想,如果你有訪問is_container類型特徵(例如從pretty printer獲取),可以使容器過載特定於容器,使用enable_if

template <template <typename...> class Container, typename ...Args> 
typename std::enable_if<is_container<Container<Args...>>::value, 
         typename Container<Args...>::value_type>::type 
print(const Container<Args...> & v) 
{ 
    /* ... */ 
}