通常没有必要限制哪些类型的模板可以被实例化。模板可以与给定的类型进行编译(并且可以正常工作),或者它不是(并且在编程器部分没有任何努力就会产生编译器错误)。
如果你需要把限制,一般类型有共同的东西,可能通过某种类型的特质,已经上市(标准库,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