2017-09-04 35 views
3

我想創建一個只接受某些類型參數的模板。對於所有剩餘類型,我希望產生編譯時錯誤消息。所以我寫了下面的如何約束模板參數

------ 1版------

template <typename T_,bool isError = true> 
struct Error { 
    static_assert(!isError, "Invalid Type"); 
}; 

template <typename T_> 
struct Wrapper : Error <T_> { 
private: 
    T_ value_; 
}; 

template <> 
struct Wrapper<int> : Error<int, false> { 
private: 
    int value_; 
}; 

int main() 
{ 
    Wrapper<int> wi; 
    Wrapper<long> wl; // I get the Invalid Type. 
} 

因爲我沒有使用類型參數T_我刪除它和代碼停止工作。

------第2版------

template <bool isError = true> 
struct Error { 
    static_assert(!isError, "Invalid Type"); 
}; 

template <typename T_> 
struct Wrapper : Error <> { 
private: 
    T_ value_; 
}; 

template <> 
struct Wrapper<int> : Error<false> { 
private: 
    int value_; 
}; 

int main() 
{ 
    Wrapper<int> wi; // I get Invalid type ????? 
    Wrapper<long> wl; // I get the Invalid Type. 
} 

我的問題是。爲什麼在刪除類型參數後發生這種情況?這個解決方案是否「乾淨」?或者存在更好的方式來實現我的意圖?

+1

你即使沒有遇到錯誤'無線/ wl'。因爲'Error'被實例化。 – Jarod42

+2

當你移除'T_'時,''Wrapper''模板的基類'Error <>'不再依賴於模板參數,所以它不需要實例化'Wrapper '本身。正如Joard指出的那樣,即使你有一個空的'main',你也會遇到錯誤。 – Praetorian

回答

4

一旦你有:

template <typename T_> 
struct Wrapper : Error <> { 
private: 
    T_ value_; 
}; 

我們可以看到,Error<>完全指定(即,所有的模板參數都知道),不像它仍然依賴地方之前。因此,編譯器會實際上繼續並無條件地實例化Error<>,這意味着此代碼將永遠不會編譯(即使沒有提及Wrapper)。當Error仍然依賴於T時,它是一個依賴類型,所以它只是在Wrapper<T>需要它的情況下實例化。

我可能會分離出的特質有點不同:

template <class T> 
struct my_trait : std::false_type {}; 

template <> 
struct my_trait<int> : std::true_type {}; 

template <class T> 
struct Wrapper { 
    static_assert(my_trait<T>::value, ""); 
}; 

int main() 
{ 
    Wrapper<int> wi; 
    Wrapper<long> wl; // I get the Invalid Type. 
} 

如果你真的想重用的錯誤信息,你可以做這樣的事情:

template <typename T> 
struct Error { 
    static_assert(my_trait<T>::value, "Invalid Type"); 
}; 

template <class T> 
struct Wrapper { 
    static constexpr auto unused = Error<T>{}; 
}; 
+0

謝謝。你的建議顯然更具可讀性且不太冗長。 –

+0

@JacintoResende謝謝。如果你覺得這個問題完全可以回答你的問題,你可以接受它,以便人們知道這個問題不需要進一步的答案。 –