2012-08-30 26 views
10

Burada BOOST_TYPEOF uygulamasının genel fikrini anlamak isterim. Demek istediğim, kod tamam olabilir, ama sanırım gerçek Boost uygulamasında olduğu gibi kod basit olmayacak. Bu nedenle, BOOST_TYPEOF uygulaması fikrini anlamak isterim. Derleme zamanında bir ifadenin türünü anlamak için derleyici işlevleri (bazı API) kullanıyor mu?BOOST_TYPEOF nasıl uygulanır?

cevap

14

Çekirdekte, Boost :: Typontal, bir ifadenin türünü bir tamsayıya dönüştürmek için bir sizeof değerlendirilmemiş bağlam kullanır ve sonra bir türe dönüştürür.

düşünün: Şimdi

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 

, herhangi char türüne veya bool olarak değerlendirilen bir ifade verilmiş, biz yazabiliriz:

TYPEOF(expr) var = expr; 

Boost :: typeof esasen bu düşüncenin bir genişleme 1997 yılında Brian Parker tarafından icat edilen; Bir tartışma ve fikrin tarihi için bkz. A Portable "typeof" Operator.


Şablonlar bu şema için bir problemdir; std::pair kadar basit bir şey, özyinesinden önce bile, yazım alanının karesini verir. Boost :: typeof şablon türü ve derleme zamanı bağlantılı listenin ardışık yuvalara onun parametre çeşitlerini kodlayarak bu çözer:

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 

Bu mevcut bir derleme zamanı bağlantılı liste uygulamasını varsayar. std::pair kod çözücüsünün, parametre türleri için gereken şekilde liste yineleyicisinden çok öğe tükettiğini fark edeceksiniz; Bu, esas olarak, değiştirilemeyen tipte bir dilde eşdeğer fonksiyonel kodun doğrudan bir çevirisidir. ... sayılı elips olarak işaretlenen iki satırda, türlerdeki sabit bir karmaşıklık seviyesiyle sınırlıyız (yani, çıkarılması istediğimiz bir tip oluşturan şablon ve tip sayısı) ile sınırlandırılmıştır. Boost :: Typeof'in bu limit için varsayılan değeri 50'dir, ancak verimliliği azaltmak ya da son derece karmaşık programlar için onu arttırmak için izin verir.

+2

sayesinde size çok! TYPEOF hakkında (make_pair ) ... Yani, tüm kombinasyonlar sadece 4 tür için yaptığınız gibi kabul edilir. Elbette hayır, buna benzer sonsuz kombinasyonlar var! O zaman nasıl yapılır? – Narek

+0

@Narek, şablonu ve parametrelerini derleme zamanı bağlantılı bir listede ardışık yuvalara kodlayarak yapılır. – ecatmur

6

Bu, sizeof'un bir derleme zamanı işleci olduğu ve şablon bağımsız değişkeni olarak kullanılabileceği fikrine dayanır. Bu şekilde her bir türe bir tamsayı atayabiliriz ve bu tamsayı türüne geri dönmek için kullanılabilir. Dezavantaj, her türün manuel olarak kaydedilmesi gerektiğidir.

Örn .:

#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'; 
} 

Çıktı:

./test 
int 
+0

Kayıt sadece yerleşik tipler için mi yapıldı? Yerleşik olmayan türden ne haber? Nasıl ele alınır? Kullanmadan önce KAYITLI OLMALIDIR? – Narek

+0

Kayıt, kullanmadan önce tüm tipler için yapılmalıdır. –

+0

Bu kod için teşekkürler. Bunu çok beğendim. Bu iyi! – Narek