Как правило, нет необходимости ограничивать типы шаблонов, с которыми можно создавать экземпляры. Либо шаблон скомпилируется с данным типом (и работает нормально), либо нет (и выдает ошибку компилятора без каких-либо усилий со стороны программиста).
Если вам нужно наложить ограничения, обычно у типов есть что-то общее, что может быть описано некоторыми уже доступными чертами типов (стандартная библиотека, 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;
}