2013-07-30 17 views
5

Giả sử tôi có giá trị không đổi (có thể là một số kiểu enum). Giả sử tôi có nhiều lớp A, B, D, v.v.Tôi có thể sử dụng số không đổi để chọn một lớp tại thời gian biên dịch, có thể sử dụng mẫu không?

Tôi có thể có thứ gì đó như thế này không?

C<1> anInstanceOfA; //This will be of type A 
C<2> anInstanceOfB; //This will be of type B 
C<3> anInstanceOfD; //This will be of type D 

Vì vậy, có thể chọn lớp dựa trên số không đổi tại thời gian biên dịch không?

Vấn đề chung là tôi đang cố gắng chọn một hàm functor dựa trên một bảng, trong đó chỉ mục là một enum. Tôi muốn tránh polymorfism nếu có thể.

Chỉnh sửa: Đối với dự án này, tôi không thể sử dụng C++ 11, dù sao đi nữa, nhờ ai trả lời trong ngữ cảnh đó, rất thú vị khi biết.
Chỉnh sửa 2: Nói chung tôi có thể có nhiều hơn 2 lớp đích, tôi đã chỉnh sửa câu hỏi của tôi

+0

Có thể đọc trên "mẫu nhà máy" – arne

Trả lời

8

Sử dụng LSP và đồng bằng C++ 98:

template <int N> class C; 
template <> class C<1> : public A {}; 
template <> class C<2> : public B {}; 
template <> class C<3> : public D {}; 

C<1> anInstanceOfA; 

Kể từ khi thừa kế nào trong C++ thỏa mãn IS-Một nguyên tắc, anInstanceOfA cả IS-Một đối tượng C<1> và IS_AN A đối tượng.

+0

Bạn nói một ngôn ngữ khác :) nhưng thực sự giải pháp này rất thanh lịch! Một vài liên kết để tôi sử dụng: http://en.wikipedia.org/wiki/Liskov_substitution_principle ... và, tôi không thể tìm thấy bất cứ điều gì về IS-A ... – Antonio

+0

Để biên dịch, tôi thêm vào '{}' , lấy 'template <> class C <1>: public A {};' ... Đúng không? – Antonio

+0

@Antonio đúng vậy. – 0x499602D2

4

Đây là một metafunction khá đơn giản:

template <int N> 
struct C { 
    typedef typename std::conditional<N == 1,A,B>::type type; 
}; 

Bạn sẽ sử dụng điều này như C<1>::type foo;.

Nếu trình biên dịch của bạn hỗ trợ C++ 11 mẫu bí danh, bạn có thể đơn giản hóa để:

template <int N> 
using C = typename std::conditional<N == 1,A,B>::type; 

và có ưa thích C<1> foo; cú pháp của bạn.

Trong tinh khiết C++ 03, thực hiện std::conditional như:

template <bool, typename A, typename> 
struct conditional { 
    typedef A type; 
}; 

template <typename A, typename B> 
struct conditional<false, A, B> { 
    typedef B type; 
}; 
+0

Bạn thậm chí có thể lồng 'std :: conditional' để tiết kiệm dung lượng. Tôi sẽ không bình luận về khả năng đọc của nó bằng cách gõ từng typedef một cách riêng biệt. – rubenvb

+0

Xin lỗi, tôi cần phải xác định (tôi có bây giờ), tôi không thể sử dụng C++ 11 – Antonio

+2

@Antonio: 'std :: conditional' không chính xác là khó viết, nhớ bạn, cũng không thực hiện nó dựa trên bất kỳ C++ 11 tính năng. – Fanael

11

Đây không phải là cách duy nhất để làm điều này, nhưng tôi hy vọng có thể chấp nhận cho mục đích của bạn:

struct A { }; 
struct B { }; 

template <int N> 
struct choices; 

template <> 
struct choices<1> { typedef A type; }; 

template <> 
struct choices<2> { typedef B type; }; 

template <int N> 
using C = typename choices<N>::type; 

Cập nhật: Để thực hiện tương tự mà không có các tính năng C++ 11, bạn nên tạo C một lớp với loại thành viên typedef bằng với loại bí danh tương ứng ở trên:

template <int N> 
struct C 
{ 
    typedef typename choices<N>::type type; 
}; 

// ... 
C<1>::type anInstanceOfA; 
C<2>::type anInstanceOfB 
+0

Cảm ơn bạn! (1 tất nhiên) Cuối cùng tôi sẽ chọn MSalters trả lời gọn nhẹ hơn, và vì lưu loại :: tại instantiation – Antonio

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