通常沒有必要限制哪些類型的模板可以被實例化。模板可以與給定的類型進行編譯(並且可以正常工作),或者它不是(並且在編程器部分沒有任何努力就會產生編譯器錯誤)。
如果你需要把限制,一般類型有共同的東西,可能通過某種類型的特質,已經上市(標準庫,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;
}
我很好奇,什麼情況下使用你對禁止模板的一些實例?我無法弄清楚爲什麼我不喜歡我的代碼被重用: -/ – Seb 2010-03-16 14:04:35
「可能會有所不同」是什麼意思?可能它們在編譯時會有所不同,或者與示例中的不同? – foraidt 2010-03-16 14:12:13
@Seb:模板可能無法正確使用某些類型。它可能不會編譯(在這種情況下,一個比任何編譯器生成的更乾淨的錯誤信息都是可取的),或者它可以編譯但不具有所需的語義(在這種情況下,防止編譯的方法很好) – jalf 2010-03-16 18:04:39