2011-01-25 28 views
9

Tôi có tình huống sau: giả sử tôi có một loạt các loại (functors) mà tôi muốn đăng ký/biên dịch trong khi biên dịch, tốt nhất là vào boost :: mpl :: vector. Bạn có biết bất kỳ mẹo nào để làm điều đó một cách độc đáo không?Đăng ký loại C++ tại thời điểm biên dịch

Mong muốn của tôi là có tệp hpp thực hiện loại functor và tệp đăng ký, trong đó macro đưa vào loại biên dịch.

Ví dụ

// registered.hpp 
REGISTER("functor1.hpp") // implementation 
REGISTER("functor2.hpp") 
... 
boost::mpl::vector<...> types; // full registration vector 

Hy vọng rằng nó có ý nghĩa. Cảm ơn bạn

Trả lời

16

Có một cách để đăng ký từng loại một và sau đó truy xuất tất cả chúng theo dạng mpl :: vector hoặc tương tự. Tôi đã học được điều này lừa trên danh sách gửi thư tăng (có lẽ từ Dave Abrahams, mặc dù tôi không thể nhớ lại chắc chắn).

Chỉnh sửa: Tôi đã học nó từ trang trình bày 28 trên https://github.com/boostcon/2011_presentations/raw/master/thu/Boost.Generic.pdf.

Tôi sẽ không sử dụng MPL trong mã để tự đặt nội dung đó.

// The maximum number of types that can be registered with the same tag. 
enum { kMaxRegisteredTypes = 10 }; 

template <int N> 
struct Rank : Rank<N - 1> {}; 

template <> 
struct Rank<0> {}; 

// Poor man's MPL vector. 
template <class... Ts> 
struct TypeList { 
    static const int size = sizeof...(Ts); 
}; 

template <class List, class T> 
struct Append; 

template <class... Ts, class T> 
struct Append<TypeList<Ts...>, T> { 
    typedef TypeList<Ts..., T> type; 
}; 

template <class Tag> 
TypeList<> GetTypes(Tag*, Rank<0>) { return {}; } 

// Evaluates to TypeList of all types previously registered with 
// REGISTER_TYPE macro with the same tag. 
#define GET_REGISTERED_TYPES(Tag) \ 
    decltype(GetTypes(static_cast<Tag*>(nullptr), Rank<kMaxRegisteredTypes>())) 

// Appends Type to GET_REGISTERED_TYPES(Tag). 
#define REGISTER_TYPE(Tag, Type)        \ 
    inline Append<GET_REGISTERED_TYPES(Tag), Type>::type  \ 
    GetTypes(Tag*, Rank<GET_REGISTERED_TYPES(Tag)::size + 1>) { \ 
    return {};            \ 
    }               \ 
    static_assert(true, "") 

dụ Cách sử dụng:

struct IntegralTypes; 
struct FloatingPointTypes; 

// Initially both type lists are empty. 
static_assert(std::is_same<GET_REGISTERED_TYPES(IntegralTypes), TypeList<>>::value, ""); 
static_assert(std::is_same<GET_REGISTERED_TYPES(FloatingPointTypes), TypeList<>>::value, ""); 

// Add something to both lists. 
REGISTER_TYPE(IntegralTypes, int); 
REGISTER_TYPE(FloatingPointTypes, float); 
static_assert(std::is_same<GET_REGISTERED_TYPES(IntegralTypes), TypeList<int>>::value, ""); 
static_assert(std::is_same<GET_REGISTERED_TYPES(FloatingPointTypes), TypeList<float>>::value, ""); 

// Add more types. 
REGISTER_TYPE(IntegralTypes, long); 
REGISTER_TYPE(FloatingPointTypes, double); 
static_assert(std::is_same<GET_REGISTERED_TYPES(IntegralTypes), TypeList<int, long>>::value, ""); 
static_assert(std::is_same<GET_REGISTERED_TYPES(FloatingPointTypes), TypeList<float, double>>::value, ""); 
+0

Bạn có liên kết đến chuỗi danh sách gửi thư không? – Xeo

+0

Thật không may tôi không thể tìm thấy các chủ đề ban đầu mà từ đó tôi đã học được các trick. –

0

Tôi sẽ không sử dụng các macro. Kỹ thuật thông thường là chỉ định nghĩa một số đối tượng có khởi tạo thực hiện đăng ký. Pitfall: bạn cần tham khảo một cái gì đó, ví dụ: gọi một chức năng, trong đơn vị biên soạn, để có nó được liên kết trong.

Cheers & h.,

+0

Lý tưởng nhất là tôi muốn đặt tất cả các loại vào thùng chứa với một dòng. Tôi biết tôi có thể làm điều đó bằng cách khác với 2-3 dòng, nhưng tôi muốn biết nếu có một thủ thuật. – Anycorn

-3

Bạn sẽ không bao giờ giải quyết mpl :: ý tưởng vector. Bạn không thể thay đổi mẫu "biến". Hãy nhớ rằng metaprogramming mẫu là một ngôn ngữ chức năng PURE. Không có tác dụng phụ nào cả.

Đối với đăng ký ... điều macro hoạt động tốt. Xác định macro để nó khai báo và khởi tạo một số biến toàn cầu nhỏ với quy trình đăng ký. Hoặc bạn có thể đi xuống con đường tôi đã làm ở đây:

How to force inclusion of "unused" object definitions in a library

Lưu ý việc sửa chữa nếu bạn đang cố gắng để làm điều đó trong một thư viện.

+0

ý tưởng của tôi giống như: lần đầu tiên đăng ký -> type1, nối thêm thứ hai để tạo kiểu 2, v.v. ... Loại cuối cùng typedef loạiN. – Anycorn

+1

'mpl :: for_each' cung cấp cho bạn các hiệu ứng phụ trong thời gian chạy. Có lẽ bạn có thể xây dựng một 'mpl :: vector' của các kiểu mà bạn có thể làm một số thứ hữu ích với; một số loại chuỗi chính sách có lẽ? Dù sao, cả hai 'for_each' và gia đình' fold' cho phép bạn xây dựng các cấu trúc có thể có hiệu ứng thời gian chạy. Yêu thích của tôi là để có một mẫu xe ô tô/cdr khuyết điểm mà kiểm tra chống lại một mpl :: contraint và hoặc là một thành viên của xe hoặc mở rộng và gọi xe của cdr. – KitsuneYMG

+0

@ymg - Có, nhưng không có cách nào để xây dựng một chuỗi mpl từ nhiều vị trí độc lập. Điều duy nhất bạn có thể làm là định nghĩa một chuỗi ở đâu đó và sử dụng nó. Vì vậy, sẽ không có chủ đề "đăng ký" nào đang diễn ra. Nó sẽ không hiệu quả hơn chỉ đơn giản là phân lớp nhà máy và mã hóa cứng các kiểu vào trong hàm tạo của nó. Ít hơn như vậy thực sự. –

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