2012-08-30 36 views
10

Ở đây tôi muốn hiểu ý tưởng chung về triển khai BOOST_TYPEOF. Tôi có nghĩa là mã có thể được OK, nhưng tôi đoán mã sẽ không được đơn giản, vì nó là trong thực tế Boost thực hiện. Do đó, tôi muốn hiểu ý tưởng triển khai BOOST_TYPEOF. Liệu nó có sử dụng các hàm biên dịch (một số API) để hiểu loại biểu thức trong thời gian biên dịch không?Cách triển khai BOOST_TYPEOF?

Trả lời

14

Tại lõi, Boost :: Typeof sử dụng ngữ cảnh không được đánh giá sizeof để chuyển đổi loại biểu thức thành số nguyên và sau đó chuyển đổi lại thành loại.

xem xét:

template<int N> struct sizer { char value[N]; }; 

sizer<1> encode(char); 
sizer<2> encode(unsigned char); 
sizer<3> encode(signed char); 
sizer<4> encode(bool); 
... 

template<int N> struct decode {}; 
template<> struct decode<1> { typedef char type; }; 
template<> struct decode<2> { typedef unsigned char type; }; 
template<> struct decode<3> { typedef signed char type; }; 
template<> struct decode<4> { typedef bool type; }; 

#define TYPEOF(expr) decode<sizeof(encode(expr))>::type 

Bây giờ, được đưa ra một biểu thức đánh giá cho bất kỳ loại char hoặc bool, chúng ta có thể viết:

TYPEOF(expr) var = expr; 

Boost :: typeof bản chất là một mở rộng của ý tưởng này , ban đầu được phát minh bởi Brian Parker vào năm 1997; xem A Portable "typeof" Operator để có một cuộc thảo luận và lịch sử của ý tưởng.


Mẫu có một chút vấn đề với lược đồ này; một cái gì đó đơn giản như std::pair cho hình vuông của không gian kiểu, ngay cả trước khi đệ quy. Boost :: typeof giải quyết điều này bằng cách mã hóa các kiểu mẫu và các loại tham số của nó vào khe liên tiếp của một danh sách liên kết thời gian biên dịch:

template<typename List> struct sizer { 
    char item0[List::at<0>]; 
    char item1[List::at<1>]; 
    char item2[List::at<2>]; 
    ... 
}; 

template<typename List> struct encode_type<List, char>: append<List, 1> {}; 
template<typename List> struct encode_type<List, unsigned char>: append<List, 2> {}; 
template<typename List, typename S, typename T> 
struct encode_type<List, std::pair<S, T> >: 
    encode_type<encode_type<append<List, 99>, S>, T> {}; 

template<typename Iter> struct decode_type<1, Iter> { 
    typedef char type; 
    typedef Iter iter; 
}; 
template<typename Iter> struct decode_type<2, Iter> { 
    typedef unsigned char type; 
    typedef Iter iter; 
}; 
template<typename Iter> struct decode_type<99, Iter> { 
    typedef typename decode_type<Iter::next::value, Iter::next>::type S; 
    typedef typename decode_type<Iter::next::value, Iter::next>::iter S_iter; 
    typedef typename decode_type<S_Iter::next::value, S_Iter::next>::type T; 
    typedef typename decode_type<S_Iter::next::value, S_Iter::next>::iter T_iter; 
    typedef std::pair<S, T> type; 
    typedef T_iter iter; 
}; 

template<typename List, typename T> 
sizer<typename encode_type<List, T>::type> encode(const T&); 

template<typename List> struct decode { 
    typedef typename decode_type<List::begin::value, List::begin>::type type; }; 

#define TYPEOF(expr) decode<list< 
    sizeof(encode(expr).item0), 
    sizeof(encode(expr).item1), 
    sizeof(encode(expr).item2), 
    ... 
    > >::type 

này giả định một thời gian biên dịch danh sách liên kết thực hiện hiện. Bạn sẽ nhận thấy rằng bộ giải mã cho std::pair tiêu thụ nhiều mục từ trình vòng lặp danh sách theo yêu cầu cho các kiểu tham số của nó; đây thực chất là bản dịch thẳng của mã chức năng tương đương trong một ngôn ngữ có các loại không thể thay đổi được.

Trên hai dòng được đánh dấu là dấu chấm lửng ... chúng tôi bị giới hạn ở mức độ phức tạp cố định trong các loại (ví dụ: số lượng mẫu và loại tạo nên loại chúng tôi muốn suy ra). Boost :: Typeof có giá trị mặc định là 50 cho giới hạn này, nhưng sẽ cho phép bạn giảm hiệu quả hoặc tăng nó cho các chương trình phức tạp điên rồ.

+2

Cảm ơn bạn rất nhiều! Điều gì về TYPEOF (make_pair ) ... Bạn có nghĩa là, rằng tất cả các kết hợp được coi là bạn đã làm cho 4 loại chỉ. Tất nhiên là không, có những kết hợp vô hạn tương tự như thế này! Sau đó làm thế nào nó được thực hiện? – Narek

+0

@Narek nó được thực hiện bằng cách mã hóa mẫu và các tham số của nó thành các khe liên tiếp trong danh sách liên kết biên dịch. – ecatmur

6

Dựa trên ý tưởng rằng sizeof là toán tử thời gian biên dịch và có thể được sử dụng làm đối số mẫu. Bằng cách này, chúng ta có thể gán một số nguyên cho mỗi loại và số nguyên đó có thể được sử dụng để lấy lại kiểu. Hạn chế là mỗi loại phải được đăng ký thủ công.

ví dụ .:

#include <boost/preprocessor/stringize.hpp> 
#include <cstddef> 
#include <iostream> 

template<size_t> struct TypeId; 

#define REGISTER_TYPE(T, id)         \ 
template<> struct TypeId<id> {         \ 
    char value[id];            \ 
    typedef T type;            \ 
    static char const* const name;        \ 
};                \ 
char const* const TypeId<id>::name = BOOST_PP_STRINGIZE(T);  \ 
TypeId<id> type_to_id(T); 

#define TYPEID_(value) TypeId<sizeof(type_to_id(value))> 
#define TYPEOF(value) typename TYPEID_(value)::type 
#define TYPENAME(value) TYPEID_(value)::name 

REGISTER_TYPE(int, 1) 
REGISTER_TYPE(unsigned int, 2) 
// and so on for all built-in types 

int main() { 
    int x; 
    TYPEOF(x) y; 
    std::cout << TYPENAME(y) << '\n'; 
} 

Output:

./test 
int 
+0

Đăng ký chỉ được thực hiện cho các loại được cài sẵn? Điều gì về các loại không được xây dựng trong? Chúng được xử lý như thế nào? Họ nên được ĐĂNG KÝ trước khi sử dụng? – Narek

+0

Đăng ký phải được thực hiện cho tất cả các loại trước khi sử dụng. –

+0

Cảm ơn mã này. Tôi thích điều này rất nhiều. Nó đẹp! – Narek