我只是想知道boost如何实现BOOST_TYPEOF(在C ++ 03中),这似乎是一个非常有用的工具。任何人都有任何想法?
另外,我认为C ++ 03本身可以提供typeof
运算符,特别是当它已经sizeof(expr)
必须知道类型时expr
的,否则它怎么能告诉我们 size ,而不知道 type ?是否真的可以知道< em> size ,不知道表达式的 type ?
如果它不知道类型,那么编译器会告诉我们 size 的内容(如果不是类型)?我的意思是,sizeof(unknowntype)
对编译器(以及人类)没有意义!
答案 0 :(得分:11)
它只使用编译器魔法。就像,海湾合作委员会的__typeof__
。对于不提供这种魔力的编译器,它提供了一个可以检测某些表达式类型的仿真,但是在完全未知类型的情况下失败。
可能的实现可能是拥有一个接受给定类型表达式的函数列表,然后使用类模板从该类型调度到一个数字。为了使函数模板将数字作为编译时实体返回,我们将其放入数组维度
template<typename> struct type2num;
template<int> struct num2type;
template<typename T> typename type2num<T>::dim &dispatch(T const&);
然后它从该数字返回到类型,以便我们的EMUL_TYPEOF
可以直接命名该类型。所以要注册一个类型,我们写
#define REGISTER_TYPE(T, N) \
template<> \
struct type2num<T> { \
static int const value = N; \
typedef char dim[N]; \
}; \
template<> \
struct num2type<N> { typedef T type; }
有了这个,你可以写
#define EMUL_TYPEOF(E) \
num2type<sizeof dispatch(E)>::type
无论何时需要注册类型,都要写
REGISTER_TYPE(int, 1);
REGISTER_TYPE(unsigned int, 2);
// ...
当然,现在您发现需要一种机制来接受vector<T>
,您事先不知道T
然后它会变得任意复杂。您可以创建一个系统,其中数字不仅仅意味着类型。这可能有用:
#define EMUL_TYPEOF(E) \
build_type<sizeof dispatch_1(E), sizeof dispatch_2(E)>::type
这可以检测类似int
的类型以及类似shared_ptr<int>
的类型 - 换句话说,不是类模板特化的类型,以及带有一个模板参数的类模板特化,通过执行某种类型系统映射
所以这就变成了
template<int N, int M>
struct build_type {
typedef typename num2tmp<N>::template apply<
typename num2type<M>::type>::type type;
};
template<int N>
struct build_type<1, N> {
typedef num2type<N>::type type;
};
我们还需要更改dispatch
模板并将其拆分为两个版本,如下所示,与REGISTER_TEMP1
一起用于注册单参数模板
template<typename T> typename type2num<T>::dim1 &dispatch_1(T const&);
template<typename T> typename type2num<T>::dim2 &dispatch_2(T const&);
#define REGISTER_TYPE(T, N) \
template<> \
struct type2num<T> { \
static int const value_dim1 = 1; \
static int const value_dim2 = N; \
typedef char dim1[value_dim1]; \
typedef char dim2[value_dim2]; \
}; \
template<> \
struct num2type<N> { typedef T type; }
#define REGISTER_TMP1(Te, N) \
template<typename T1> \
struct type2num< Te<T1> > { \
static int const value_dim1 = N; \
static int const value_dim2 = type2num<T1>::value_dim2; \
typedef char dim1[value_dim1]; \
typedef char dim2[value_dim2]; \
}; \
template<> struct num2tmp<N> { \
template<typename T1> struct apply { \
typedef Te<T1> type; \
}; \
}
现在注册std::vector
模板和两个int
变体看起来像
REGISTER_TMP1(std::vector, 2);
// ... REGISTER_TMP1(std::list, 3);
REGISTER_TYPE(int, 1);
REGISTER_TYPE(unsigned int, 2);
// ... REGISTER_TYPE(char, 3);
您可能还希望为每种类型注册多个数字,每个const / volatile组合可以注册一个数字,或者每种类型可能需要多个数字来记录*
,&
等。您还希望支持vector< vector<int> >
,因此模板参数也需要多个数字,使build_type
递归调用自身。由于您可以创建任意长整数列表,因此无论如何都可以将任何内容编码到该序列中,因此这取决于您在如何表示这些事物方面的创造力。
最后,您可能正在重新实现BOOST_TYPEOF:)
答案 1 :(得分:6)
从内存来看,boost :: typeof是通过一些?:hacks实现的。首先,您从一个可以转换为任何其他类的类开始,例如
class something {
public:
template<typename T> operator const T&() {
return *(T*)0;
}
};
?:规则规定如果双方都有相同的类型,那么结果就是该类型。否则,如果一种类型可以转换为另一种类型,那就是结果类型。所以通过做
true ? something() : expr;
结果类型是(一个const引用)expr的类型 - 但expr实际上从未被计算过,因为它位于false分支上。那么你将它传递给已经有参数推导的地方,比如函数参数。
template<typename T> void x(const T& t) {
// T is the type of expr.
}
这有点复杂,因为从内存来看,C ++ 03没有参考折叠,所以它可能比这个例子更复杂 - 最有可能使用SFINAE和类型特征。
如何将其转换为可以传递给模板的实际编译时类型,我不知道。至于提供decltype()的C ++ 03,C ++ 03语言存在更大的问题,如ODR和声明/定义顺序,没有移动语义等,这比不提供decltype要糟糕得多。 / p>
答案 2 :(得分:0)
它被定义为:
#define BOOST_TYPEOF(Expr) \
boost::type_of::decode_begin<BOOST_TYPEOF_ENCODED_VECTOR(Expr) >::type
我不知道细节,但它似乎在某种表中查找类型,并扩展为(表项):: type
不,如果不知道类型,就无法知道尺寸。只是没有人想过将typeof添加到C ++ 03。
答案 3 :(得分:0)
由于boost是作为源代码分发的(并且BOOST_TYPEOF在任何情况下都是头文件实现),你当然可以看一下。它有许多特定于编译器的条件编译,因此答案是它是特定于编译器的。
答案 4 :(得分:0)
虽然与typeof
不完全相同,但C ++ 0x有decltype
。