[英]Prevent templated member function from being instantiated for a given type
我有一個模板化的矩陣類,我明確地為各種POD類型和自定義類類型實例化。 然而,一些成員函數對於一些這樣的自定義類型沒有意義。 例如:
Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class
我可以阻止選擇類型的Matrix
對象的LoadFile
函數(它是成員函數)的實例化嗎? 到目前為止,我通過使LoadFile
成為友元函數然后顯式控制其實例化來避免這個問題。 但是我想知道當LoadFile
是Matrix
的成員函數時我是否可以這樣做。
第一個問題是你是否真的需要控制它。 如果他們在存儲My_custom_class
的矩陣上調用該成員函數會發生什么? 你能在你的班級(或模板)中提供支持,以便會員功能有效嗎?
如果你真的想要禁止某些特定類型的成員函數的使用,那么你可以使用特化來阻止特定的實例化:
template <typename T>
struct test {
void foo() {}
};
template <>
inline void test<int>::foo() = delete;
或者甚至只是將static_assert
添加到通用實現中,驗證允許或禁止哪些類型的前提條件?
template <typename T>
struct test {
void foo() {
static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
"Only allowed for int and double");
// regular code
}
};
使用std::enable_if
,這是我能想到的最好的
template< typename T >
struct Matrix {
template< typename T >
Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()
只輸入int
compile而其他不輸入。
我可以阻止選擇類型的Matrix對象的LoadFile函數(它是成員函數)的實例化嗎?
這里最好的選擇是使用static_assert
,當您嘗試在使用阻塞類型實例化的類的版本中調用該方法時,該static_assert
會產生編譯器錯誤。 使用std::enable_if
以及有選擇地“禁用”方法本身的其他方法將要求您使用和不使用相關方法創建類的部分或完全特化,以防止編譯器錯誤。 例如,AFAIK,您不能執行以下操作:
template <typename T>
struct test
{
static const bool value = false;
};
template<>
struct test<double>
{
static const bool value = true;
};
template<typename T>
struct example
{
void print() { cout << "Printing value from print()" << endl; }
typename enable_if<test<T>::value, T>::type another_print()
{
cout << "Printing value from another_print()" << endl;
return T();
}
};
如果您嘗試實例化一個example<int>
等,則在實例化對象類型時最終會出現編譯器錯誤。 你不能簡單地調用example<int>::print()
並且沒關系,只有在你選擇調用example<int>::another_print()
才會遇到問題。 example<T>
專業化可以幫助您解決問題,但這可能有點混亂。 正如最初推測的那樣, static_assert
可能是最簡單的處理方式,並向最終用戶提供一條很好的消息,解釋出現了什么問題。
請記住,創建編譯器錯誤是目標,並且它是一個很好的。 如果阻止某個方法被實例化,並且最終用戶決定調用它,那么無論哪種方式都會出現編譯器錯誤。 沒有static_assert
的版本會留下很多令人static_assert
,因為你的類的用戶試圖解析一個可能非常詳細的編譯器錯誤消息,其中static_assert
方法是直接的和重點。
如果所選的一組類型在編譯時是已知的,並且您正在使用帶有類型別名的編譯器的c ++ 11, 統一初始化和constexpr (例如gcc 4.7),那么您可以使代碼更加清晰(來自上面的例子由yngum):
template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template< typename T >
struct Matrix {
template< typename T >
//std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
Matrix<enable_if_t<std::is_integral<T>{}>>
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();
但請注意此代碼的兼容性,因為這些功能最近才得到支持,而且一些編譯器還沒有。 您可以在此處查看有關c ++ 11編譯器支持的更多信息。
如果你可以使用( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 )中的TypeLists - Loki你可以實現類似的東西:
template<bool>
struct Static_Assert;
template<>
struct Static_Assert<true>{};
class B{};
template<typename T>
class A{
public:
A(){
Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
}
};
然后您的HasType將是這樣的:
template<typename T, typename TList>
struct HasType{
enum { value = 0+HasType< T, typename TList::Tail >::value };
};
template<typename T>
struct HasType< T, NullType >{
enum { value = 0 };
};
template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
enum { value = 1 };
};
在列表中,您可以添加要阻止作為模板參數傳遞的類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.