2012-02-15 52 views
6

Giữ câu hỏi cũ. Xem dưới đây để giải quyết. Nó có lẽ là một cái gì đó đơn giản, nhưng vẫn còn. Tôi có sau C++ 11 đoạn mã:C++ 11 Các mẫu tham số mẫu có biến thể

#include <vector> 

template <typename... Ts> 
struct typelist 
{ 
}; 

template <typename T> 
struct EventContainer 
{ 
    typedef T Type; 
    /// TODO. Ring buffer 
    std::vector<T> container; 

    void push(const T& t) 
    { 
     EventContainer<T>::container.push_back(t); 
    } 

    virtual ~EventContainer() 
    { 
    } 
}; 


template <template <typename...> class TL> 
class EventStorage: 
     public EventContainer<Ts>... 
{ 

}; 

class Event1 
{ 
}; 

class Event2 
{ 
}; 

typedef typelist<Event1,Event2> Events12; 

int main() 
{ 
    EventStorage<Events12> ev; 

    return 0; 
} 

Làm thế nào tôi có thể làm cho EventStorage kế thừa EventContainer templeted với mỗi loại trong typelist. Tôi có thể làm điều đó với Loki :: library, nhưng tôi muốn sử dụng C++ 11 với các mẫu variadic. Cảm ơn bạn.

Độ phân giải 1: Sửa lỗi EventStorage vấn đề mẫu mẫu. Điều này sẽ làm cho EventStorage, nhiều kế thừa tất cả EventContainer được tô điểm với mỗi loại Ts.

template <typename...> 
class EventStorage 
{ 
}; 

template <typename... Ts> 
class EventStorage < typelist<Ts...> >: 
     public EventContainer<Ts>... 
{ 

}; 

Bây giờ tôi phải biên dịch lỗi thời gian, trên main() sau:

int main() 
{ 
    EventStorage<Events12> ev; 
    Event1 ev1; 
    ev.push(ev1); 

    return 0; 
} 

In function ‘int main()’: 
error: request for member ‘push’ is ambiguous 
error: candidates are: void EventContainer<T>::push(const T&) [with T = Event2] 
error: void EventContainer<T>::push(const T&) [with T = Event1] 

Tại sao trình biên dịch được nhầm lẫn? Sau khi tất cả tôi đẩy với loại cụ thể. GCC 4.6.1 tại đây.

Resolution2: Như @Matthieu M. đề nghị tôi có thể trình bày một phương pháp chuyển tiếp int EventStorage, nhưng với chi phí của một cuộc gọi functin thêm:

template <typename T> 
void push(const T& t) 
{ 
    EventContainer<T>::push(t); 
} 

Theo Alexandrescu, trình biên dịch sẽ tối ưu hóa cuộc gọi chuyển tiếp này miễn là tham số là tham chiếu. Bây giờ câu hỏi đã chính thức bị đóng :)

Trả lời

6

Có lý do nào để giới thiệu typelist ngay từ đầu không?

template <typename T> struct Template { void push(T) {} }; 

template <typename... Args> 
class Storage: public Template<Args>... 
{ 
public: 
    // forwarding... 
    template <typename T> 
    void push(T t) { 
    Template<T>& me = *this; 
    me.push(t); 
    } 
}; 

int main() { 
    Storage< int, char > storage; 
} 

này works và bạn có thể typedef cả Storage<...> bit.

EDIT: Theo dõi các nhận xét về khả năng kết hợp "các loại".

Có hai giải pháp:

template <typename...> struct CombineStorage; 

template <typename... A, typename... B> 
struct CombineStorage<Storage<A...>, Storage<B...>> { 
    typedef Storage<A..., B...> type; 
}; 

Hoặc đơn giản là cung cấp một bộ chuyển đổi typelist:

template <typename... Args> 
class Storage<typelist<Args...>>: public Storage<Args...> {}; 
+0

Tôi ước mình có thể tạo hạt các loại hoán vị 'Sự kiện' khác nhau. Ví dụ. 'typedef typelist pumpEvents;' 'typedef typelist displayEvents;' Nhưng khi bạn đặt nó theo cách đó, tôi muốn kết hợp hai 'typelists', nếu nhu cầu lưu trữ để lưu trữ cả hai. –

+0

Tôi đã chỉnh sửa câu trả lời của mình để bao gồm bộ điều hợp 'typelist' và bộ kết hợp bộ nhớ. –

+0

Cảm ơn bạn rất nhiều. Tôi sẽ cố gắng, sau khi tôi giải quyết vấn đề mơ hồ này từ những người khác của tôi trả lời bình luận. Nó là rất lạ. Không phải là 'đẩy()' gots quá tải? –

1

Tại thời điểm này, bạn sẽ không bao giờ thậm chí đi qua một instantiation typelist đến EventStorage, chỉ là typelist mẫu. Hiện tại, có không có gói loại nào để mở rộng.

Tuy nhiên, bạn sẽ có thể giải nén các typelist với một chuyên môn hóa và hợp tác với loại gói khác:

template <typename...> class EventStorage; 

template <typename Head, typename... Tail> class EventStorage<Head, Tail...> 
    : public EventContainer<Head>, EventStorage<Tail...> 
{ 
    using EventContainer<Head>::push; 
    using EventStorage<Tail...>::push; 
}; 

// allows you to pass typelists for convenience 
template <typename... TL> class EventStorage<typelist<TL...>> 
    : public EventStorage<TL...> 
{ 
    using EventStorage<TL...>::push; 
}; 

Các using tờ khai chỉ cần kéo tất cả các phương pháp push vào các thiết lập tình trạng quá tải tương tự, mà dường như làm việc cho tôi.

Cách khác là thêm phương thức mẫu (có thể chỉ đến chuyên môn typelist toplevel) chuyển tiếp rõ ràng tới this->EventContainer<T>::push, nhưng sẽ yêu cầu kết hợp loại chính xác.

+0

Vâng, tôi đã tự tìm ra. Tuy nhiên tôi nhận được sự mơ hồ bây giờ. Giả sử rằng thêm/thay thế các bản sửa lỗi của bạn, tôi nhận được thông báo này: 'lỗi: yêu cầu thành viên 'đẩy' là mơ hồ ' ' lỗi: ứng cử viên là: void EventContainer :: push (const T &) [with T = Event2] ' ' khoảng trống EventContainer :: push (const T &) [với T = EVENT1] ' chính là: ' int main() { \t EventStorage ev; \t Sự kiện1 ev1; \t ev.push (ev1); \t trả về 0; } ' –

+0

Vâng, tôi không thêm bit đẩy, nhưng phải mất một chút khó khăn - chỉnh sửa ngay bây giờ ... – Useless

+0

Ah, bây giờ tôi thấy rằng có một chút hiểu lầm. Tôi muốn kế thừa mọi 'EventContainer' mỗi mẫu được đặt theo từng loại trong' typelist'. Mã của tôi thực sự là: ' mẫu lớp EventStorage { }; template lớp EventStorage >: \t \t công EventContainer ... { }; ' Chỉnh sửa: Tôi không thể định dạng sh * t tại đây. Tôi xin lỗi: ( –

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