C ++ 03中缺少typeof运算符?

时间:2010-12-26 12:08:10

标签: c++ templates boost metaprogramming typeof

我只是想知道boost如何实现BOOST_TYPEOF(在C ++ 03中),这似乎是一个非常有用的工具。任何人都有任何想法?

另外,我认为C ++ 03本身可以提供typeof运算符,特别是当它已经sizeof(expr) 必须知道类型时expr,否则它怎么能告诉我们 size ,而不知道 type ?是否真的可以知道< em> size ,不知道表达式的 type

如果它不知道类型,那么编译器会告诉我们 size 的内容(如果不是类型)?我的意思是,sizeof(unknowntype)对编译器(以及人类)没有意义!

5 个答案:

答案 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>的类型 - 换句话说,不是类模板特化的类型,以及带有一个模板参数的类模板特化,通过执行某种类型系统映射

  • 如果第一个数字产生1,则第二个数字指定一个类型;否则
  • 第一个数字指定模板,第二个数字指定第一个类型模板参数

所以这就变成了

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