Подтвердить что ты не робот

Силовой тип шаблона С++

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

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

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

Это только примеры, допустимые типы могут отличаться.

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

Спасибо.

4b9b3361

Ответ 1

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

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

Ответ 2

Быстрая идея, я уверен, что есть более эффективные подходы:

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

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

Ответ 4

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


Если вам нужно ввести ограничения, обычно типы имеют что-то общее, что может быть описано некоторыми имеющимися типами признаков, которые уже доступны (стандартная библиотека, boost::type_traits), или вы можете создать для них новый тип.

Например, здесь шаблонный класс, который допускает только целые типы, используя std::numeric_limits для его проверки (если вы пишете свой собственный числовой тип, вы можете специализироваться на том, чтобы он также работал с вашим новым целым типом). static_assert - только С++ 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 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;
}

Ответ 5

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

Ответ 6

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

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

template <double> class MyClass
{};

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

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

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