2017-02-17 85 views
2

我有以下類別:我如何專注/重載一個模板函數的模板類型

template <class... T> 
class thing {}; 

template <class T> 
class container { 
    public: 
     container() { 
      std::cout << "normal constructor" << std::endl; 
     } 
}; 

我可以寫的container<int>以這種方式構造一個完整的專業化:

template <> 
container<int>::container() { 
    std::cout << "int constructor" << std::endl; 
} 

我希望能夠爲container<thing<T>>定義一個類似的構造函數。我想我試圖寫一個模板函數的偏特這裏是我試圖(這是非法的。):

template <class T> 
container<thing<T>>::container() { 

} 

這並不編譯。

我不完全確定解決這個問題的正確方法是什麼,模板類函數的重載和專業化之間的界限變得模糊。這可以微不足道地解決,還是需要type_traits(std::enable_if)?我該如何解決這個問題?

回答

7

你不能偏專門的構造函數,但你不必一定要分專業滿級。

這可以簡單地解決或將需要type_traits/enable_if?我該如何解決這個問題?

委託構造函數和標籤調度可以解決此限制。
它遵循最小,工作示例:

#include<iostream> 

template <class... T> 
class thing {}; 

template <class T> 
class container { 
    template<typename> 
    struct tag {}; 

    template<typename U> 
    container(int, tag<thing<U>>) { 
     std::cout << "thing<U>" << std::endl; 
    } 

    container(char, tag<T>) { 
     std::cout << "normal constructor" << std::endl; 
    } 

public: 
    container(): container(0, tag<T>{}) {} 
}; 

int main() { 
    container<int> c1; 
    container<thing<int>> c2{}; 
} 

看到它的wandbox


請注意,如果你想有兩個以上的委託構造函數,從中挑選合適的人了,你可以輕鬆地擴展它。
作爲一個例子:

#include<iostream> 

template <class... T> 
class thing {}; 

template<typename> struct tag {}; 
template<int N> struct prio: prio<N-1> {}; 
template<> struct prio<0> {}; 

template <class T> 
class container {  
    template<typename U> 
    container(prio<2>, tag<thing<U>>) { 
     std::cout << "thing<U>" << std::endl; 
    } 

    container(prio<1>, tag<double>) { 
     std::cout << "double" << std::endl; 
    } 

    container(prio<0>, tag<T>) { 
     std::cout << "normal constructor" << std::endl; 
    } 

public: 
    container(): container(prio<2>{}, tag<T>{}) {} 
}; 

int main() { 
    container<int> c1; 
    container<double> c2; 
    container<thing<int>> c3{}; 
} 

查看它wandbox

+1

非常優雅的解決方案(恕我直言) – max66

+0

@ max66謝謝。整個班級的部分專業化很快就會導致代碼重複,如果可能的話,我通常會盡量避免它。 – skypjack

+0

@ max66僅在多個_specialized_構造函數的情況下添加更多細節。我希望你也喜歡它。 ;-) – skypjack

4

你不能偏專門的構造函數,但可以部分專業類的全

template <class T> 
class container<thing<T>> 
{ 
    public: 
     container() { } 
}; 
+0

這樣我就不得不完全(重新)定義類,對嗎? – user2079802

+0

@ user2079802 - 是;但是,如果您需要(重新)定義的類的部分很小,與完整的類相比,您可以創建一個只包含要定義/重新定義的部分的基類。 – max66

+0

@ user2079802 - 更要看skypjack的解決方案:不偏專門的構造函數,但相結合的標籤調度和委託的構造,就可以解決問題,而無需重新定義完整的類 – max66