Тип силы шаблона C++

У меня есть основной шаблонный класс, но я хотел бы ограничить тип специализации к ряду классов или типов. например:

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

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

Это - просто примеры, позволенные типы могут варьироваться.

Это даже возможно? Если это, как сделать так?

Спасибо.

12
задан gregseth 16 March 2010 в 14:01
поделиться

6 ответов

Другая версия - оставить неопределенным для запрещенных типов

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
17
ответ дан 2 December 2019 в 04:16
поделиться

Взгляните на библиотеку проверки концепции Boost: http: // www. boost.org/doc/libs/1_42_0/libs/concept_check/concept_check.htm

6
ответ дан 2 December 2019 в 04:16
поделиться

Я не уверен в этом, но вы можете добавить другую специализацию шаблона для двойного шаблона

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

template <double> class MyClass
{};

, который будет работать для вашего примера, но не для общего случая.

В общем, я бы добавил компиляцию assert для проверки на нежелательные типы.

Надеюсь, это поможет.

1
ответ дан 2 December 2019 в 04:16
поделиться

Обычно нет необходимости ограничивать типы шаблонов, с которыми можно создавать экземпляры. Либо шаблон компилируется с заданным типом (и работает нормально), либо нет (и вызывает ошибку компилятора без каких-либо усилий со стороны программиста).


Если вам нужно ввести ограничения, обычно у типов есть что-то общее, что может быть описано некоторыми признаками типа, которые уже доступны (стандартная библиотека, 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;
}
2
ответ дан 2 December 2019 в 04:16
поделиться

Просто быстрая идея, я уверен, что есть подходы получше:

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];
};

Возможно, лучше, однако, поместить жирный комментарий над вашим кодом, чтобы удержать пользователей от инстанцирования с неправильными типами :-)

8
ответ дан 2 December 2019 в 04:16
поделиться

Существуют различные приемы, позволяющие проверить некоторые вещи, в зависимости от того, каковы ваши критерии для того, чтобы инстанцирование было разрешено или нет. На практике вы должны использовать для этого библиотеку более высокого уровня, например Boost's Concept Check.

1
ответ дан 2 December 2019 в 04:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: