У меня есть основной шаблонный класс, но я хотел бы ограничить тип специализации к ряду классов или типов. например:
template <typename T>
class MyClass
{
.../...
private:
T* _p;
};
MyClass<std::string> a; // OK
MYCLass<short> b; // OK
MyClass<double> c; // not OK
Это - просто примеры, позволенные типы могут варьироваться.
Это даже возможно? Если это, как сделать так?
Спасибо.
Другая версия - оставить неопределенным для запрещенных типов
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
Взгляните на библиотеку проверки концепции Boost: http: // www. boost.org/doc/libs/1_42_0/libs/concept_check/concept_check.htm
Я не уверен в этом, но вы можете добавить другую специализацию шаблона для двойного шаблона
class MyClass
{
.../...
private:
T* _p;
};
template <double> class MyClass
{};
, который будет работать для вашего примера, но не для общего случая.
В общем, я бы добавил компиляцию assert для проверки на нежелательные типы.
Надеюсь, это поможет.
Обычно нет необходимости ограничивать типы шаблонов, с которыми можно создавать экземпляры. Либо шаблон компилируется с заданным типом (и работает нормально), либо нет (и вызывает ошибку компилятора без каких-либо усилий со стороны программиста).
Если вам нужно ввести ограничения, обычно у типов есть что-то общее, что может быть описано некоторыми признаками типа, которые уже доступны (стандартная библиотека, 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;
}
Если вы планируете поддерживать лишь горстку произвольных типов, не имеющих ничего общего (как видно из вашего гипотетического примера), одним из способов является использование списков типов. Опять же, boost может значительно упростить задачу, но вот как вы можете свернуть свою собственную (это только половина пути, потребуется дополнительная работа, чтобы сделать объявление списка типов красивее).
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;
}
Просто быстрая идея, я уверен, что есть подходы получше:
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];
};
Возможно, лучше, однако, поместить жирный комментарий над вашим кодом, чтобы удержать пользователей от инстанцирования с неправильными типами :-)
Существуют различные приемы, позволяющие проверить некоторые вещи, в зависимости от того, каковы ваши критерии для того, чтобы инстанцирование было разрешено или нет. На практике вы должны использовать для этого библиотеку более высокого уровня, например Boost's Concept Check.