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

Naw*_*waz 7 c++ templates boost metaprogramming typeof

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

另外,我想C++ 03本身也有提供typeof运营商,尤其是当它已经具有sizeof(expr)必须要知道类型expr同时,否则怎么回事能告诉我们的大小,不知道类型?难道真的有可能知道大小,而不知道表达式的类型

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

Joh*_*itb 11

它只使用编译器魔法.就像,海湾合作委员会的__typeof__.对于不提供这种魔术的编译器,它提供了一个可以检测某些表达式类型的仿真,但是在完全未知类型的情况下失败.

可能的实现可以是具有接受给定类型的表达式的函数列表,然后使用类模板从该类型分派到数字.为了使函数模板将数字作为编译时实体返回,我们将其放入数组维度

template<typename> struct type2num;
template<int> struct num2type;
template<typename T> typename type2num<T>::dim &dispatch(T const&);
Run Code Online (Sandbox Code Playgroud)

然后它从该数字返回到类型,以便我们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; }
Run Code Online (Sandbox Code Playgroud)

有了这个,你可以写

#define EMUL_TYPEOF(E) \
  num2type<sizeof dispatch(E)>::type
Run Code Online (Sandbox Code Playgroud)

无论什么时候需要注册一个类型,你都要写

REGISTER_TYPE(int, 1);
REGISTER_TYPE(unsigned int, 2);
// ...
Run Code Online (Sandbox Code Playgroud)

当然,现在你发现你需要一种机制来接受vector<T>,你T事先不知道然后它变得任意复杂.您可以创建一个系统,其中数字不仅仅意味着类型.这可能有效:

#define EMUL_TYPEOF(E) \
  build_type<sizeof dispatch_1(E), sizeof dispatch_2(E)>::type
Run Code Online (Sandbox Code Playgroud)

这可以通过某种系统的映射来检测类似的类型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;
};
Run Code Online (Sandbox Code Playgroud)

我们还需要更改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; \
    }; \
  }
Run Code Online (Sandbox Code Playgroud)

注册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);
Run Code Online (Sandbox Code Playgroud)

您可能还希望为每种类型注册多个数字,每个const/volatile组合一个数字,或者每种类型可能需要多个数字用于记录*,&等等.您也希望支持vector< vector<int> >,因此模板参数也需要多个数字,以build_type递归方式调用自身.由于您可以创建任意长整数列表,因此无论如何都可以将任何内容编码到该序列中,因此您可以根据自己的创造力来表示这些内容.

最后,你可能重新实现BOOST_TYPEOF :)


Pup*_*ppy 6

从内存来看,boost :: typeof是通过一些?:hacks实现的.首先,你从一个可以转换为任何其他类的类开始,比如

class something {
public:
    template<typename T> operator const T&() {
        return *(T*)0;
    }
};
Run Code Online (Sandbox Code Playgroud)

?:规则规定如果双方具有相同的类型,则结果为该类型.否则,如果一种类型可以转换为另一种类型,那就是结果类型.所以通过做

true ? something() : expr;
Run Code Online (Sandbox Code Playgroud)

结果类型是(一个const引用)expr的类型 - 但expr实际上从未被计算过,因为它在假分支上.那么你将它传递给已经有参数推导的地方,比如函数参数.

template<typename T> void x(const T& t) {
    // T is the type of expr.
}
Run Code Online (Sandbox Code Playgroud)

这有点复杂,因为从内存来看,C++ 03没有引用崩溃,所以它可能比这个例子更复杂 - 最有可能使用SFINAE和类型特征.

如何将其转换为可以传递到模板的实际编译时类型,我不知道.对于提供decltype()的C++ 03,C++ 03语言存在更大的问题,如ODR和声明/定义顺序,没有移动语义等,这比不提供decltype要糟糕得多.

  • @Kos:因为你花了一生的时间告诉编译器它已经知道的事情,但碰巧是在其他翻译单元中,或者必须被声明然后定义,或者任何旧的废话,这是程序员时间的巨大浪费.@Nawaz:我所说的是C++,03或0x,已经拥有如此多的wtfs,而03年没有提供decltype在"委员会吸烟是什么?"的名单上相当低. (3认同)