2012-08-30 12 views
10

ここでは、BOOST_TYPEOFを実装する一般的な考え方を理解したいと思います。私はコードがOKかもしれないことを意味しますが、実際のBoostの実装ではコードが単純ではないと思います。したがって、BOOST_TYPEOF実装の考え方を理解したいと思います。コンパイル時に式の型を理解するためにコンパイラ関数(いくつかのAPI)を使用していますか?BOOST_TYPEOFの実装方法は?

答えて

14

コアでは、Boost :: Typeofはsizeof評価されていないコンテキストを使用して式の型を整数に変換し、次にそれを型に変換します。

を考えてみましょう:今すぐ

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 

、あらゆるcharタイプやboolに評価される式を考えると、我々は書くことができます。

TYPEOF(expr) var = expr; 

ブースト:: typeof演算は、基本的にこのアイデアを拡張したものです1997年にBrian Parkerによって最初に発明されたものです。アイデアの議論と歴史については、A Portable "typeof" Operatorを参照してください。


このスキームでは、テンプレートに問題があります。 std::pairという単純なものは、再帰の前であっても型空間の2乗を与えます。ブースト:: typeof演算は、コンパイル時にリンクされたリストの連続するスロットにテンプレートタイプとそのパラメータの型を符号化することによって、これを解決:

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 

これは、既存のコンパイル時にリンクされたリストの実装を想定しています。 std::pairのデコーダでは、パラメータの型に必要な数だけリストイテレータから項目を消費します。これは本質的に、変更不可能な型を持つ言語の同等の機能コードの直接の変換です。

省略記号...としてマークされている2つの行では、タイプが一定の複雑さ(つまり、推測したいタイプを構成するテンプレートとタイプの数)に制限されています。 Boost :: Typeofのデフォルト値は50ですが、複雑なプログラムでは効率を上げるために減らしたり、効率を上げることができます。

+2

ありがとう! TYPEOF(make_pair )についてどういうことですか...あなたは、4種類のタイプのすべての組み合わせが考慮されることを意味しますか?もちろん、いいえ、これに似た無限の組み合わせがあります!そしてそれはどのように行われますか? – Narek

+0

@ Narekこれは、テンプレートとそのパラメータをコンパイル時のリンクリストの連続するスロットにエンコードすることによって行われます。 – ecatmur

6

sizeofはコンパイル時の演算子であり、テンプレート引数として使用できるという考え方に基づいています。このようにして、各型に整数を代入することができ、その整数を使用して型に戻すことができます。欠点は、各タイプを手動で登録する必要があることです。

例えば:

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

出力:あなたは非常に多くの

./test 
int 
+0

登録はビルトインタイプの場合にのみ行われますか?非組み込み型はどうですか?彼らはどのように扱われますか?彼らは事前に登録する必要がありますか? – Narek

+0

登録する前に、すべての種類の登録が必要です。 –

+0

このコードをありがとう。私はこれをとても好きだった。いいね! – Narek

関連する問題