11

这里想了解一下实现BOOST_TYPEOF的大致思路。我的意思是代码可能没问题,但我想代码不会简单,因为它是真正的 Boost 实现。所以想了解一下BOOST_TYPEOF实现的思路。它是否使用编译器函数(某些 API)来理解编译时表达式的类型?

4

2 回答 2

16

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;

Boost::Typeof 本质上是这个想法的扩展,最初是由 Brian Parker 在 1997 年发明的;有关该想法的讨论和历史,请参阅便携式“typeof”运算符。


模板对于这个方案来说有点问题。即使在递归之前,也可以简单地std::pair给出类型空间的平方。Boost::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从列表迭代器中消耗与其参数类型所需的一样多的项目;这本质上是对具有非可变类型的语言的等效功能代码的直接翻译。

在标记为省略号的两行中,...我们被限制在一个固定的类型复杂度水平(即构成我们想要推断的类型的模板和类型的数量)。Boost::Typeof 对此限制的默认值为 50,但可以让您降低它以提高效率或增加它以用于疯狂复杂的程序。

于 2012-08-30T14:49:59.203 回答
8

它基于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
于 2012-08-30T14:56:41.240 回答