2015-08-31 2 views
8

Короче:Дайте общий тип перечисления в качестве аргумента шаблона

Есть ли способ, что я могу кормить General шаблонный класс с чем-то, что только представляют enum тип? Что-то вроде:

template <typename T> struct General {}; 
struct EnumSpecific : General<any_enum_type> {}; 

<int> слишком много/не работает в моем случае.


Мой конкретный случай:

  • шаблонного Holder класс обрабатывает любые данные в общем виде.
  • Класс абстрактных классов General реализует конкретные алгоритмы, основанные на поведении Holder s.
  • шаблона спецификации General (как IntSpecific, DoubleSpecific, StringSpecific, MoreSophisticatedTypeSpecific ..) определить, как иметь дело с некоторыми конкретными Holder типов.
  • Как я могу правильно определить спецификацию EnumSpecific?

Здесь boilt вниз код делает мою проблему произойти:

// A templated value holder: 
template <typename T> 
class Holder { 
public: 
    Holder(T const& t) : _value(t) {}; 
    // generic methods 
    void generics() {}; 
    // methods concerning the value: 
    void set(T const& t /*, setInfo */) { 
     // .. check for an actual change, notify buddies of the change.. 
     _value = t; 
    }; 
    T value(/*readInfo*/) { 
     // .. do stuff depending on how/why the value is read.. 
     return _value; 
    }; 
private: 
    T _value; 
}; 
// (in reality, all `generics` methods come from a parent, untemplated class) 

// A generic process involving such `Holder`s: 
template <typename T> 
class General { 
public: 
    typedef bool /* or anything */ KnownReturnTypes; 
    General(Holder<T>* const a 
      , Holder<T>* const b) 
     : _a(a) 
     , _b(b) 
    {}; 
    void methods() { 
     // Use common behavior of all `Holder`'s 
     _a->generics(); 
     // .. or methods that rely on the actual values: 
     KnownReturnTypes knr(valuedMethods()); 
     if (knr) {} else {} 
     // ... 
    }; 
    // Use polymorphism to adapt to each situation.. 
    virtual KnownReturnTypes valuedMethods() = 0; 
protected: 
    Holder<T>* _a; 
    Holder<T>* _b; 
}; 

// Example of specialization for integral types (there might be others) 
class IntSpecific : General<int> { 
public: 
    IntSpecific(Holder<int>* const a 
       , Holder<int>* const b) 
     : General<int>(a, b) 
    {}; 
    // implement the valuedMethods: 
    virtual KnownReturnTypes valuedMethods() { 
     return _a->value() > _b->value(); // dummy 
    } 
}; 

// Specialization for enum types: 
// * * * class EnumSpecific : General<any_enum_type> { // does not exist * * 
class EnumSpecific : General<int> { 
public: 
    EnumSpecific(Holder<int>* const a 
       , Holder<int>* const b) 
     : General<int>(a, b) 
    {}; 
    // only use properties and methods offered by an enum type: 
    virtual KnownReturnTypes valuedMethods() { 
     return _a->value() == _b->value(); // dummy 
    } 
}; 

// One particular case 
typedef enum {One, Two, Three} Enum; 
typedef Holder<Enum> EnumHolder; 


int main() { 

    // Check that `IntSpecific` works fine. 
    Holder<int>* i(new Holder<int>(3)); 
    Holder<int>* j(new Holder<int>(5)); 
    IntSpecific is(i, j); // ok. 

    // Try the `EnumSpecific` 
    EnumHolder* a(new EnumHolder { One }); 
    EnumHolder* b(new EnumHolder { Two }); 
    EnumSpecific es(static_cast<Holder<int>*>(a) // invalid cast 
        , static_cast<Holder<Enum>*>(b)); // unexpected type 
    // This is because the compiler doesn't know enough about what 
    // EnumSpecific actually *is*. How to tell him more about it? 


    return EXIT_SUCCESS; 
} 

Что я должен кормить аргумент шаблона с в EnumSpecific : General<??>, чтобы сделать вещи ясно для компилятора?

Нужно ли использовать какую-то концепцию enum_type и более сложные инструменты от общего программирования?

+3

C++ 11 дает 'зЬй :: is_enum': http://en.cppreference.com/w/cpp/types/is_enum –

+0

@AlanStokes Как мило с его стороны! Но это не может самостоятельно подать параметр шаблона, не так ли? Как это может помочь мне выполнить бросок? –

+1

Его можно было бы выгодно использовать с 'enable_if'. И 'basic_type' может помочь с вашим приведением, хотя, признаюсь, на этом этапе я немного потерял ваш код. –

ответ

7

Мы можем выполнить это с помощью std::enable_if и std::is_enum. В качестве образца это класс, который будет использовать тип перечисления в качестве параметра шаблона.

#include <type_traits> 
enum Enum { FOO, BAR}; 

template<typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr> 
class Test {}; 

int main() 
{ 
    Test<Enum> a; // ok 
    Test<double> b; // error 
} 
+0

Arf! Я не могу заставить это работать. Является ли '#include ', которого должно хватить для использования вашего кода? gcc говорит 'error: no type named 'type' in 'struct std :: enable_if '. –

+0

Это ошибка, которую вы должны получить. если 'enable_if' передано false, то typedef' type' не существует и создает ошибку компилятора. Должна быть заметка после ошибки, например: 'note: при замене аргументов предшествующего шаблона в параметр шаблона непигового типа ...' – NathanOliver

+0

Wops! Конечно. Я просто запутался, потому что 'clang' обнаружил ошибку в строке' template'. Это по-прежнему выглядит для меня волшебным: знаете ли вы о хорошем роуминге программирования на языке C++? Что-то идет дальше 'template ' и покрывает эти новые C++ 11 удивительные вещи? –

Смежные вопросы