2015-08-31 17 views
8

Nói tóm lại:tặng một kiểu enum chung như mẫu đối số

Có cách nào tôi có thể nuôi một lớp templated General với một cái gì đó mà chỉ đại diện cho một loại enum? Một cái gì đó như:

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

<int> quá nhiều/không hoạt động trong trường hợp của tôi.


trường hợp cụ thể của tôi:

  • Một templated Holder lớp xử lý bất kỳ loại dữ liệu trong một cách chung chung.
  • Lớp trừu tượng General triển khai các thuật toán cụ thể dựa trên hành vi của Holder.
  • Mẫu số kỹ thuật của General (như IntSpecific, DoubleSpecific, StringSpecific, MoreSophisticatedTypeSpecific ..) xác định làm thế nào để đối phó với một số Holder loại bê tông.
  • Làm cách nào để xác định đúng thông số EnumSpecific?

Dưới đây là boilt xuống mã làm cho vấn đề của tôi xảy ra:

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

tôi nên ăn gì các mẫu tranh cãi với trong EnumSpecific : General<??> để làm cho mọi việc rõ ràng cho trình biên dịch?

Tôi có cần sử dụng một số loại khái niệm enum_type và các công cụ phức tạp hơn từ lập trình chung không?

+3

C++ 11 mang đến cho bạn 'std :: is_enum': http://en.cppreference.com/w/cpp/types/is_enum –

+0

@AlanStokes Làm thế nào ngọt ngào của anh ta! Nhưng điều này không thể tự cung cấp thông số mẫu, phải không? Làm thế nào điều này có thể giúp tôi thực hiện các diễn viên? –

+1

Có thể sử dụng lợi nhuận với 'enable_if'. Và 'inner_type' có thể giúp dàn diễn viên của bạn, mặc dù tôi thú nhận rằng tôi đã bị mất một chút trong mã của bạn ở giai đoạn đó. –

Trả lời

7

Chúng tôi có thể thực hiện việc này với std::enable_ifstd::is_enum. Như một mẫu, đây là một lớp sẽ lấy kiểu enum làm tham số mẫu.

#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! Tôi không thể làm việc này. '#include ' có đủ để sử dụng mã của bạn không? gcc nói 'lỗi: không có loại nào có tên là‘ type ’trong‘ struct std :: enable_if '. –

+0

Đó là lỗi bạn sẽ nhận được. nếu 'enable_if' được thông qua false thì kiểu' type' typedef không tồn tại và nó tạo ra một lỗi trình biên dịch. Nên có một lưu ý sau khi lỗi như: 'lưu ý: trong khi thay thế các đối số mẫu trước đó thành tham số mẫu không kiểu ...' – NathanOliver

+0

Wops! Tất nhiên. Tôi chỉ bị bối rối vì 'clang' đặt lỗi trên dòng' template'. Điều này vẫn có vẻ kỳ diệu với tôi: Bạn có nhận thức được một C++ tốt lập trình chung chung chuyển vùng không? Một cái gì đó đi xa hơn 'mẫu ' và bao gồm những nội dung tuyệt vời mới C++ 11? –

Các vấn đề liên quan