2010-03-16 62 views
12

我有一個基本的模板類,但我想限制專業化的類型爲一組類或類型。例如:強制類型的C++模板

template <typename T> 
class MyClass 
{ 
.../... 
private: 
    T* _p; 
}; 

MyClass<std::string> a; // OK 
MYCLass<short> b;  // OK 
MyClass<double> c;  // not OK 

這些僅僅是示例,允許的類型可能會有所不同。

這可能嗎?如果是這樣,怎麼做?

謝謝。

+1

我很好奇,什麼情況下使用你對禁止模板的一些實例?我無法弄清楚爲什麼我不喜歡我的代碼被重用: -/ – Seb 2010-03-16 14:04:35

+0

「可能會有所不同」是什麼意思?可能它們在編譯時會有所不同,或者與示例中的不同? – foraidt 2010-03-16 14:12:13

+3

@Seb:模板可能無法正確使用某些類型。它可能不會編譯(在這種情況下,一個比任何編譯器生成的更乾淨的錯誤信息都是可取的),或者它可以編譯但不具有所需的語義(在這種情況下,防止編譯的方法很好) – jalf 2010-03-16 18:04:39

回答

17

另一個版本是離開它未定義禁種

template<typename T> 
struct Allowed; // undefined for bad types! 

template<> struct Allowed<std::string> { }; 
template<> struct Allowed<short> { }; 

template<typename T> 
struct MyClass : private Allowed<T> { 
    // ... 
}; 

MyClass<double> m; // nono 
+2

+1。事實上,我比第一個答案更喜歡這個解決方案。 – paercebal 2010-03-16 22:32:28

+0

@paercebal,謝謝夥計xD – 2010-03-17 07:23:41

+0

不客氣。無論如何,自從我上次發表評論以來,你的答案就成爲了選定的答案,顯然,我不是唯一一個能夠看到它的價值的人:--P – paercebal 2010-03-17 14:09:19

1

有各種各樣的技巧,允許檢查一些事情,這取決於你的標準是什麼實例化被允許。在實踐中,您應該爲Boost的Concept Check等人使用更高級別的庫。

8

Yust一個快速的想法,我敢肯定有更好的方法:

template <typename T> struct protector { 
static const int result = 1; 
}; 

template <> struct protector<double> { 
static const int result = -1; 
}; 

template <typename T> 
class MyClass 
{ 
    private: 
    char isfine[protector<T>::result]; 
}; 

這可能是更好的,但是,把脂肪評論過你的代碼,以保持用戶從錯誤類型的實例: - )

+0

您擊敗了我來吧。這裏使用的習語稱爲* type traits *。 – 2010-03-16 14:11:17

+4

是否有另一種方法可以做到這一點,而不會在每個實例中產生char [1]數組的成本?就個人而言,我會使用BOOST_STATIC_ASSERT。 – 2010-03-16 14:13:16

+2

在'char'之前加上'typedef'。 – Ari 2010-03-16 14:31:02

1

林不知道這一點,但您可以添加其他模板專用雙 模板

class MyClass 
{ 
.../... 
private: 
    T* _p; 
}; 

template <double> class MyClass 
{}; 

這會爲你工作例如,但不適用於一般情況。

通常,我會添加一個編譯斷言來檢查不需要的類型。

希望它有幫助。

2

通常沒有必要限制哪些類型的模板可以被實例化。模板可以與給定的類型進行編譯(並且可以正常工作),或者它不是(並且在編程器部分沒有任何努力就會產生編譯器錯誤)。


如果你需要把限制,一般類型有共同的東西,可能通過某種類型的特質,已經上市(標準庫,boost::type_traits)來描述,也可以創建一個新的類型特徵他們。

例如,以下是一個只允許整數類型的模板類,使用std::numeric_limits來檢查它(如果您編寫自己的數值類型,則可以將其專門化,以便它也適用於您的新整數類型)。 static_assert僅爲C++ 0x,如果不可用,請使用BOOST_STATIC_ASSERT或其他一些技巧。

#include <limits> 
#include <string> 

template <class T> 
class X 
{ 
    static_assert(std::numeric_limits<T>::is_integer, "X can be only instantiated with integer types"); 
    //... 
}; 

int main() 
{ 
    X<int> xi; 
    X<char> xc; 
    //X<double> xd; 
    //X<std::string> xs; 
} 

如果你只打算支持任意類型的任何共同之處一小撮(這是從你的假設的例子明顯),一個方法是使用類型串。再次提升可能會讓任務變得更容易,但這裏是您如何推出自己的(這只是中途,需要額外的工作來宣佈類型列表更漂亮)。

struct no_type {}; 

template <class T, class U = no_type> 
struct t_list 
{ 
    typedef T head; 
    typedef U tail; 
}; 

//trait to check if two types are identical 
template <class T, class U> 
struct is_same 
{ 
    static const bool value = false; 
}; 

template <class T> 
struct is_same<T, T> 
{ 
    static const bool value = true; 
}; 

//compile-time recursion to check if T matches any type in list L 
template <class T, class L> 
struct in_type_list 
{ 
    static const bool value = 
     is_same<T, typename L::head>::value || in_type_list<T, typename L::tail>::value; 
}; 

//terminates recursion 
template <class T> 
struct in_type_list<T, no_type> 
{ 
    static const bool value = false; 
}; 

template <class T> 
class X 
{ 
    typedef t_list<double, t_list<int, t_list<char> > > allowed_types; //double, int, char 

    //poor man's static_assert 
    typedef int check_type [in_type_list<T, allowed_types>::value ? 1 : -1]; 
    //... 
}; 

int main() 
{ 
    X<char> xc; 
    X<int> xi; 
    X<double> xd; 
    //X<float> xf; 
}