簡體   English   中英

多種類型的類模板專業化

[英]Class Template specialization for multiple types

我發現了幾個類似問題的問題,但找不到針對我特殊情況的直接答案。 模板的整個語法讓我非常困惑,因此我可能會誤解了一些東西。

我有一個應該接受每種類型的類模板。 簡單的例子:

template <class T>
class State {
  public:
    void set(T newState);
    T get();
  private:
    T state;
};

template <class T>
void State<T>::set(T newState){
  state = newState;
}

template <class T>
T State<T>::get(){
  return state;
}

現在,我想為一組類型提供一個專門的模板,為這些類型添加一個附加功能。 根據到目前為止的發現,我可以利用所謂的type_traits,但是如何精確地使用它們來實現這一點對我來說仍然是個謎。

如果有這種針對int類型的專業化,但是我不想允許所有其他int和float變體,而不是只為int類型編寫這種特性。 我找到了std :: is_arithmetic,但不知道如何利用它來實現這一目標。

template <>
class State <int> {
  public:
    void set(int newState);
    int get();
    int multiplyState(int n);
  private:
    int state;
};

void State<int>::set(int newState){
  state = newState;
}

int State<int>::get(){
  return state;
}

int State<int>::multiplyState(int n){
  return state*n;
}

您可以將部分模板專業化與SFINAE結合使用以實現以下目的:

#include <type_traits>

template <class T, typename = void>
class State
{
    T state;

public:
    void set(T newState)
    {
        state = newState;
    }

    T get()
    {
      return state;
    }
};

template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{
    T state;

public:
    void set(int newState)
    {
        state = newState;
    }

    int get()
    {
        return state;
    }

    int multiplyState(int n)
    {
        return state*n;
    }
};

這里的例子

這里的竅門在於使用第二個模板參數(可以不命名,並使用默認參數)。 當使用類模板的特殊化(例如State<some_type> ,編譯器必須弄清楚應該使用哪個模板。 為此,它必須以某種方式將給定的模板參數與每個模板進行比較,並確定最匹配的模板參數。

實際完成此匹配的方法是,嘗試從給定的模板參數中推導出每個局部專業化的參數。 例如,在State<int>的情況下,模板參數將為intvoid (后者之所以存在是因為主模板第二個參數的默認參數)。 然后,我們嘗試為我們唯一的局部專業化推論

template <typename T>
class State<T, std::enable_if_t<std::is_arithmetic_v<T>>>;

從模板參數int, void 我們的部分專業化具有單個參數T ,可以直接從第一個模板參數int推導得出。 至此,我們已經完成了所有參數的推導(這里只有一個)。 現在我們將推導的參數替換為部分專業化: State<T, std::enable_if_t<std::is_arithmetic_v<T>>> 我們以State<int, void>結尾,該狀態與int, void的初始參數列表匹配。 因此,部分模板專業化適用。

現在,如果改為編寫State<some_type> ,其中some_type不是算術類型,那么直到成功將局部專業化的參數推導出為some_type ,過程將是相同的。 同樣,我們將參數代入部分特殊化State<T, std::enable_if_t<std::is_arithmetic_v<T>>> 但是, std::is_arithmetic_v<some_type>現在將為false ,這將導致未定義std::enable_if_t<…>且替換失敗。 因為在這種情況下替換失敗不是錯誤 ,所以這僅意味着部分專業化不是此處的選擇,而是將使用主模板。

如果存在多個匹配的局部專業,則必須對它們進行排名以選擇最佳匹配。 實際的過程非常復雜,但是通常歸結為選擇最具體的專業。

盡管對於像這樣的小示例,可以對整個類進行特殊化,但在更復雜的情況下,您可能希望避免重復所有成員,以便可以將一個成員添加到特殊化中。 為此,一種常見的技術是從公共基類繼承額外的成員函數,並且僅專門使基類具有或不具有成員。 您必須使用CRTP,以便基類成員函數知道如何訪問派生類。 看起來像:

// StateBase only contains the extra multiplyState member when State tells it to
// define it, based on T being an arithmetic type
template <class D, class T, bool has_multiply>
struct StateBase {};

template <class D, class T>
struct StateBase<D, T, true> {
    T multiplyState(int n) {
        return static_cast<D*>(this)->state * n;
    }
};

template <class T>
class State : public StateBase<State<T>, T, std::is_arithmetic<T>::value> {
  public:
    // no need to duplicate these declarations and definitions
    void set(T newState);
    T get();
  private:
    // note that we write State::StateBase to force the injected-class-name to be found
    friend struct State::StateBase;
    T state;
};

Coliru連結

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM